Index: lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp =================================================================== --- lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp +++ lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp @@ -70,13 +70,20 @@ const StringRef CPU; bool HasNopl; uint64_t MaxNopLength; + +protected: + bool Is64Bit; + public: - 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"; + X86AsmBackend(const Target &T, bool Is64Bit, StringRef CPU) + : MCAsmBackend(), CPU(CPU), Is64Bit(Is64Bit) { + // Only some 32 bit CPUs don't support true long nop instructions. + HasNopl = + Is64Bit || (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. @@ -345,7 +352,9 @@ // 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); + + // The alternative instructions are nops only on 32 bit CPUs. + assert(HasNopl || (MaxNopLength <= 7 && !Is64Bit)); // Emit as many largest nops as needed, then emit a nop of the remaining // length. @@ -370,14 +379,14 @@ class ELFX86AsmBackend : public X86AsmBackend { public: uint8_t OSABI; - ELFX86AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) - : X86AsmBackend(T, CPU), OSABI(OSABI) {} + ELFX86AsmBackend(const Target &T, bool Is64Bit, uint8_t OSABI, StringRef CPU) + : X86AsmBackend(T, Is64Bit, CPU), OSABI(OSABI) {} }; class ELFX86_32AsmBackend : public ELFX86AsmBackend { public: ELFX86_32AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) - : ELFX86AsmBackend(T, OSABI, CPU) {} + : ELFX86AsmBackend(T, false, OSABI, CPU) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ false, OSABI, ELF::EM_386); @@ -387,7 +396,7 @@ class ELFX86_X32AsmBackend : public ELFX86AsmBackend { public: ELFX86_X32AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) - : ELFX86AsmBackend(T, OSABI, CPU) {} + : ELFX86AsmBackend(T, false, OSABI, CPU) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ false, OSABI, @@ -398,7 +407,7 @@ class ELFX86_IAMCUAsmBackend : public ELFX86AsmBackend { public: ELFX86_IAMCUAsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) - : ELFX86AsmBackend(T, OSABI, CPU) {} + : ELFX86AsmBackend(T, false, OSABI, CPU) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ false, OSABI, @@ -409,7 +418,7 @@ class ELFX86_64AsmBackend : public ELFX86AsmBackend { public: ELFX86_64AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) - : ELFX86AsmBackend(T, OSABI, CPU) {} + : ELFX86AsmBackend(T, true, OSABI, CPU) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ true, OSABI, ELF::EM_X86_64); @@ -417,13 +426,9 @@ }; class WindowsX86AsmBackend : public X86AsmBackend { - bool Is64Bit; - public: WindowsX86AsmBackend(const Target &T, bool is64Bit, StringRef CPU) - : X86AsmBackend(T, CPU) - , Is64Bit(is64Bit) { - } + : X86AsmBackend(T, is64Bit, CPU) {} Optional getFixupKind(StringRef Name) const override { return StringSwitch>(Name) @@ -471,7 +476,6 @@ enum { CU_NUM_SAVED_REGS = 6 }; mutable unsigned SavedRegs[CU_NUM_SAVED_REGS]; - bool Is64Bit; unsigned OffsetSize; ///< Offset of a "push" instruction. unsigned MoveInstrSize; ///< Size of a "move" instruction. @@ -776,7 +780,7 @@ public: DarwinX86AsmBackend(const Target &T, const MCRegisterInfo &MRI, StringRef CPU, bool Is64Bit) - : X86AsmBackend(T, CPU), MRI(MRI), Is64Bit(Is64Bit) { + : X86AsmBackend(T, Is64Bit, CPU), MRI(MRI) { memset(SavedRegs, 0, sizeof(SavedRegs)); OffsetSize = Is64Bit ? 8 : 4; MoveInstrSize = Is64Bit ? 3 : 2; Index: test/MC/X86/x86_long_nop.s =================================================================== --- test/MC/X86/x86_long_nop.s +++ test/MC/X86/x86_long_nop.s @@ -3,6 +3,7 @@ # RUN: llvm-mc -filetype=obj -arch=x86 -triple=x86_64-apple-darwin10.0 %s | llvm-objdump -d -no-show-raw-insn - | FileCheck %s # RUN: llvm-mc -filetype=obj -arch=x86 -triple=i686-apple-darwin8 %s | llvm-objdump -d -no-show-raw-insn - | FileCheck %s # RUN: llvm-mc -filetype=obj -arch=x86 -triple=i686-pc-linux-gnu -mcpu=slm %s | llvm-objdump -d -no-show-raw-insn - | FileCheck --check-prefix=SLM %s +# RUN: llvm-mc -filetype=obj -arch=x86-64 -triple=x86_64-pc-linux-gnu -mcpu=i386 %s | llvm-objdump -d -no-show-raw-insn - | FileCheck --check-prefix=64BIT %s # Ensure alignment directives also emit sequences of 15-byte NOPs on processors # capable of using long NOPs. @@ -23,3 +24,9 @@ # SLM-NEXT: 16: nop # SLM-NEXT: 1d: nop # SLM-NEXT: 20: inc + +# Ensure that for x86-64 we emit true long nops regardless of -mcpu value. +# 64BIT: 0: inc +# 64BIT-NEXT: 2: nop +# 64BIT-NEXT: 11: nop +# 64BIT-NEXT: 20: inc