diff options
-rw-r--r-- | llvm/include/llvm/MC/MCAssembler.h | 10 | ||||
-rw-r--r-- | llvm/include/llvm/MC/MCStreamer.h | 14 | ||||
-rw-r--r-- | llvm/lib/MC/MCAsmStreamer.cpp | 9 | ||||
-rw-r--r-- | llvm/lib/MC/MCAssembler.cpp | 23 | ||||
-rw-r--r-- | llvm/lib/MC/MCMachOStreamer.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/MC/MCNullStreamer.cpp | 3 |
6 files changed, 73 insertions, 3 deletions
diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h index 4527f3c28d3..882929f2eee 100644 --- a/llvm/include/llvm/MC/MCAssembler.h +++ b/llvm/include/llvm/MC/MCAssembler.h @@ -195,12 +195,16 @@ class MCAlignFragment : public MCFragment { /// cannot be satisfied in this width then this fragment is ignored. unsigned MaxBytesToEmit; + /// EmitNops - true when aligning code and optimal nops to be used for filling + bool EmitNops; + public: MCAlignFragment(unsigned _Alignment, int64_t _Value, unsigned _ValueSize, - unsigned _MaxBytesToEmit, MCSectionData *SD = 0) + unsigned _MaxBytesToEmit, bool _EmitNops, + MCSectionData *SD = 0) : MCFragment(FT_Align, SD), Alignment(_Alignment), Value(_Value),ValueSize(_ValueSize), - MaxBytesToEmit(_MaxBytesToEmit) {} + MaxBytesToEmit(_MaxBytesToEmit), EmitNops(_EmitNops) {} /// @name Accessors /// @{ @@ -217,6 +221,8 @@ public: unsigned getMaxBytesToEmit() const { return MaxBytesToEmit; } + unsigned getEmitNops() const { return EmitNops; } + /// @} static bool classof(const MCFragment *F) { diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index b104b9ad570..696d024aa85 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -232,6 +232,20 @@ namespace llvm { unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0) = 0; + /// EmitCodeAlignment - Emit nops until the byte alignment @p ByteAlignment + /// is reached. + /// + /// This used to align code where the alignment bytes may be executed. This + /// can emit different bytes for different sizes to optimize execution. + /// + /// @param ByteAlignment - The alignment to reach. This must be a power of + /// two on some targets. + /// @param MaxBytesToEmit - The maximum numbers of bytes to emit, or 0. If + /// the alignment cannot be reached in this many bytes, no bytes are + /// emitted. + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0) = 0; + /// EmitValueToOffset - Emit some number of copies of @p Value until the /// byte offset @p Offset is reached. /// diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 6add1b4abaa..07a9553ff1d 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -134,6 +134,9 @@ public: unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0); + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0); + virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value = 0); @@ -513,6 +516,12 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, EmitEOL(); } +void MCAsmStreamer::EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) { + // FIXME: a hack for now to only work for x86 using the 0x90 nop opcode. + EmitValueToAlignment(ByteAlignment, 0x90, 1, MaxBytesToEmit); +} + void MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset, unsigned char Value) { // FIXME: Verify that Offset is associated with the current section. diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index 528c5c025d5..2c698e76f92 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -42,6 +42,8 @@ STATISTIC(EmittedFragments, "Number of emitted assembler fragments"); static void WriteFileData(raw_ostream &OS, const MCSectionData &SD, MachObjectWriter &MOW); +static uint64_t WriteNopData(uint64_t Count, MachObjectWriter &MOW); + /// isVirtualSection - Check if this is a section which does not actually exist /// in the object file. static bool isVirtualSection(const MCSection &Section) { @@ -1058,6 +1060,19 @@ void MCAssembler::LayoutSection(MCSectionData &SD) { SD.setFileSize(Address - SD.getAddress()); } +/// WriteNopData - Write optimal nops to the output file for the \arg Count +/// bytes. This returns the number of bytes written. It may return 0 if +/// the \arg Count is more than the maximum optimal nops. +/// +/// FIXME this is X86 32-bit specific and should move to a better place. +static uint64_t WriteNopData(uint64_t Count, MachObjectWriter &MOW) { + // FIXME for now just use the 0x90 nop opcode byte. + for (uint64_t i = 0; i < Count; i++) + MOW.Write8 (uint8_t(0x90)); + + return Count; +} + /// WriteFileData - Write the \arg F data to the output file. static void WriteFileData(raw_ostream &OS, const MCFragment &F, MachObjectWriter &MOW) { @@ -1081,6 +1096,14 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F, "' is not a divisor of padding size '" + Twine(AF.getFileSize()) + "'"); + // See if we are aligning with nops, and if so do that first to try to fill + // the Count bytes. Then if that did not fill any bytes or there are any + // bytes left to fill use the the Value and ValueSize to fill the rest. + if (AF.getEmitNops()) { + uint64_t NopByteCount = WriteNopData(Count, MOW); + Count -= NopByteCount; + } + for (uint64_t i = 0; i != Count; ++i) { switch (AF.getValueSize()) { default: diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp index 797be86caf2..a7a8a5daed9 100644 --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -137,6 +137,8 @@ public: virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0); + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0); virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value = 0); @@ -357,7 +359,20 @@ void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, if (MaxBytesToEmit == 0) MaxBytesToEmit = ByteAlignment; new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, - CurSectionData); + false /* EmitNops */, CurSectionData); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > CurSectionData->getAlignment()) + CurSectionData->setAlignment(ByteAlignment); +} + +void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) { + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + // FIXME the 0x90 is the default x86 1 byte nop opcode. + new MCAlignFragment(ByteAlignment, 0x90, 1, MaxBytesToEmit, + true /* EmitNops */, CurSectionData); // Update the maximum alignment on the current section if necessary. if (ByteAlignment > CurSectionData->getAlignment()) diff --git a/llvm/lib/MC/MCNullStreamer.cpp b/llvm/lib/MC/MCNullStreamer.cpp index 46e9ebfa886..ab6179907e8 100644 --- a/llvm/lib/MC/MCNullStreamer.cpp +++ b/llvm/lib/MC/MCNullStreamer.cpp @@ -55,6 +55,9 @@ namespace { unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0) {} + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0) {} + virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value = 0) {} |