Skip to content

Commit

Permalink
Alternative to long nops for X86 CPUs, by Andrey Turetsky
Browse files Browse the repository at this point in the history
Make X86AsmBackend generate smarter nops instead of a bunch of 0x90 for code alignment for CPUs which don't support long nop instructions.
Differential Revision: http://reviews.llvm.org/D14178


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253557 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
alexey-bataev committed Nov 19, 2015
1 parent 23915cf commit 3e00ff9
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 21 deletions.
46 changes: 32 additions & 14 deletions lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,19 @@ class X86ELFObjectWriter : public MCELFObjectTargetWriter {
class X86AsmBackend : public MCAsmBackend {
const StringRef CPU;
bool HasNopl;
const uint64_t MaxNopLength;
uint64_t MaxNopLength;
public:
X86AsmBackend(const Target &T, StringRef CPU)
: MCAsmBackend(), CPU(CPU), MaxNopLength(CPU == "slm" ? 7 : 15) {
X86AsmBackend(const Target &T, StringRef CPU) : MCAsmBackend(), CPU(CPU) {
HasNopl = CPU != "generic" && CPU != "i386" && CPU != "i486" &&
CPU != "i586" && CPU != "pentium" && CPU != "pentium-mmx" &&
CPU != "i686" && CPU != "k6" && CPU != "k6-2" && CPU != "k6-3" &&
CPU != "geode" && CPU != "winchip-c6" && CPU != "winchip2" &&
CPU != "c3" && CPU != "c3-2";
// Max length of true long nop instruction is 15 bytes.
// Max length of long nop replacement instruction is 7 bytes.
// Taking into account SilverMont architecture features max length of nops
// is reduced for it to achieve better performance.
MaxNopLength = (!HasNopl || CPU == "slm") ? 7 : 15;
}

unsigned getNumFixupKinds() const override {
Expand Down Expand Up @@ -279,7 +283,7 @@ void X86AsmBackend::relaxInstruction(const MCInst &Inst, MCInst &Res) const {
/// bytes.
/// \return - true on success, false on failure
bool X86AsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
static const uint8_t Nops[10][10] = {
static const uint8_t TrueNops[10][10] = {
// nop
{0x90},
// xchg %ax,%ax
Expand All @@ -302,17 +306,31 @@ bool X86AsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
{0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
};

// This CPU doesn't support long nops. If needed add more.
// FIXME: Can we get this from the subtarget somehow?
// FIXME: We could generated something better than plain 0x90.
if (!HasNopl) {
for (uint64_t i = 0; i < Count; ++i)
OW->write8(0x90);
return true;
}
// Alternative nop instructions for CPUs which don't support long nops.
static const uint8_t AltNops[7][10] = {
// nop
{0x90},
// xchg %ax,%ax
{0x66, 0x90},
// lea 0x0(%esi),%esi
{0x8d, 0x76, 0x00},
// lea 0x0(%esi),%esi
{0x8d, 0x74, 0x26, 0x00},
// nop + lea 0x0(%esi),%esi
{0x90, 0x8d, 0x74, 0x26, 0x00},
// lea 0x0(%esi),%esi
{0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00 },
// lea 0x0(%esi),%esi
{0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00},
};

// Select the right NOP table.
// FIXME: Can we get if CPU supports long nops from the subtarget somehow?
const uint8_t (*Nops)[10] = HasNopl ? TrueNops : AltNops;
assert(HasNopl || MaxNopLength <= 7);

// 15 is the longest single nop instruction. Emit as many 15-byte nops as
// needed, then emit a nop of the remaining length.
// Emit as many largest nops as needed, then emit a nop of the remaining
// length.
do {
const uint8_t ThisNopLength = (uint8_t) std::min(Count, MaxNopLength);
const uint8_t Prefixes = ThisNopLength <= 10 ? 0 : ThisNopLength - 10;
Expand Down
8 changes: 1 addition & 7 deletions test/MC/X86/x86_nop.s
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,7 @@ inc %eax
inc %eax

// CHECK: 0: 40 incl %eax
// CHECK: 1: 90 nop
// CHECK: 2: 90 nop
// CHECK: 3: 90 nop
// CHECK: 4: 90 nop
// CHECK: 5: 90 nop
// CHECK: 6: 90 nop
// CHECK: 7: 90 nop
// CHECK: 1: 8d b4 26 00 00 00 00 leal (%esi), %esi
// CHECK: 8: 40 incl %eax


Expand Down

0 comments on commit 3e00ff9

Please sign in to comment.