diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86ATTInstPrinter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86ATTInstPrinter.cpp --- a/llvm/lib/Target/X86/MCTargetDesc/X86ATTInstPrinter.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86ATTInstPrinter.cpp @@ -46,7 +46,7 @@ if (CommentStream) HasCustomInstComment = EmitAnyX86InstComments(MI, *CommentStream, MII); - printInstFlags(MI, OS); + printInstFlags(MI, OS, STI); // Output CALLpcrel32 as "callq" in 64-bit mode. // In Intel annotation it's always emitted as "call". diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.h b/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.h --- a/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.h +++ b/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.h @@ -33,7 +33,8 @@ raw_ostream &O); protected: - void printInstFlags(const MCInst *MI, raw_ostream &O); + void printInstFlags(const MCInst *MI, raw_ostream &O, + const MCSubtargetInfo &STI); void printOptionalSegReg(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printVKPair(const MCInst *MI, unsigned OpNo, raw_ostream &OS); }; diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp --- a/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp @@ -18,10 +18,11 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/Casting.h" -#include +#include "llvm/Support/raw_ostream.h" #include +#include using namespace llvm; @@ -349,7 +350,8 @@ } } -void X86InstPrinterCommon::printInstFlags(const MCInst *MI, raw_ostream &O) { +void X86InstPrinterCommon::printInstFlags(const MCInst *MI, raw_ostream &O, + const MCSubtargetInfo &STI) { const MCInstrDesc &Desc = MII.get(MI->getOpcode()); uint64_t TSFlags = Desc.TSFlags; unsigned Flags = MI->getFlags(); @@ -379,6 +381,16 @@ O << "\t{disp8}"; else if (Flags & X86::IP_USE_DISP32) O << "\t{disp32}"; + + // Address-Size override prefix + if (Flags & X86::IP_HAS_AD_SIZE && + !X86_MC::needsAddressSizeOverride( + *MI, STI, X86II::getMemoryOperandNo(TSFlags), TSFlags)) { + if (STI.hasFeature(X86::Mode16Bit) || STI.hasFeature(X86::Mode64Bit)) + O << "\taddr32\t"; + else if (STI.hasFeature(X86::Mode32Bit)) + O << "\taddr16\t"; + } } void X86InstPrinterCommon::printVKPair(const MCInst *MI, unsigned OpNo, diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86IntelInstPrinter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86IntelInstPrinter.cpp --- a/llvm/lib/Target/X86/MCTargetDesc/X86IntelInstPrinter.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86IntelInstPrinter.cpp @@ -40,7 +40,7 @@ void X86IntelInstPrinter::printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &OS) { - printInstFlags(MI, OS); + printInstFlags(MI, OS, STI); // In 16-bit mode, print data16 as data32. if (MI->getOpcode() == X86::DATA16_PREFIX && diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp --- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -156,65 +156,6 @@ return MCFixup::getKindForSize(Size, isPCRel); } -/// \param Op operand # of the memory operand. -/// -/// \returns true if the specified instruction has a 16-bit memory operand. -static bool is16BitMemOperand(const MCInst &MI, unsigned Op, - const MCSubtargetInfo &STI) { - const MCOperand &Base = MI.getOperand(Op + X86::AddrBaseReg); - const MCOperand &Index = MI.getOperand(Op + X86::AddrIndexReg); - - unsigned BaseReg = Base.getReg(); - unsigned IndexReg = Index.getReg(); - - if (STI.hasFeature(X86::Mode16Bit) && BaseReg == 0 && IndexReg == 0) - return true; - if ((BaseReg != 0 && - X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg)) || - (IndexReg != 0 && - X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg))) - return true; - return false; -} - -/// \param Op operand # of the memory operand. -/// -/// \returns true if the specified instruction has a 32-bit memory operand. -static bool is32BitMemOperand(const MCInst &MI, unsigned Op) { - const MCOperand &BaseReg = MI.getOperand(Op + X86::AddrBaseReg); - const MCOperand &IndexReg = MI.getOperand(Op + X86::AddrIndexReg); - - if ((BaseReg.getReg() != 0 && - X86MCRegisterClasses[X86::GR32RegClassID].contains(BaseReg.getReg())) || - (IndexReg.getReg() != 0 && - X86MCRegisterClasses[X86::GR32RegClassID].contains(IndexReg.getReg()))) - return true; - if (BaseReg.getReg() == X86::EIP) { - assert(IndexReg.getReg() == 0 && "Invalid eip-based address."); - return true; - } - if (IndexReg.getReg() == X86::EIZ) - return true; - return false; -} - -/// \param Op operand # of the memory operand. -/// -/// \returns true if the specified instruction has a 64-bit memory operand. -#ifndef NDEBUG -static bool is64BitMemOperand(const MCInst &MI, unsigned Op) { - const MCOperand &BaseReg = MI.getOperand(Op + X86::AddrBaseReg); - const MCOperand &IndexReg = MI.getOperand(Op + X86::AddrIndexReg); - - if ((BaseReg.getReg() != 0 && - X86MCRegisterClasses[X86::GR64RegClassID].contains(BaseReg.getReg())) || - (IndexReg.getReg() != 0 && - X86MCRegisterClasses[X86::GR64RegClassID].contains(IndexReg.getReg()))) - return true; - return false; -} -#endif - enum GlobalOffsetTableExprKind { GOT_None, GOT_Normal, GOT_SymDiff }; /// Check if this expression starts with _GLOBAL_OFFSET_TABLE_ and if it is @@ -463,7 +404,7 @@ // 16-bit addressing forms of the ModR/M byte have a different encoding for // the R/M field and are far more limited in which registers can be used. - if (is16BitMemOperand(MI, Op, STI)) { + if (X86_MC::is16BitMemOperand(MI, Op, STI)) { if (BaseReg) { // For 32-bit addressing, the row and column values in Table 2-2 are // basically the same. It's AX/CX/DX/BX/SP/BP/SI/DI in that order, with @@ -672,25 +613,10 @@ emitByte(0xF2, OS); // Emit the address size opcode prefix as needed. - bool NeedAddressOverride; - uint64_t AdSize = TSFlags & X86II::AdSizeMask; - if ((STI.hasFeature(X86::Mode16Bit) && AdSize == X86II::AdSize32) || - (STI.hasFeature(X86::Mode32Bit) && AdSize == X86II::AdSize16) || - (STI.hasFeature(X86::Mode64Bit) && AdSize == X86II::AdSize32)) { + bool NeedAddressOverride = + X86_MC::needsAddressSizeOverride(MI, STI, MemoryOperand, TSFlags); + if (Flags & X86::IP_HAS_AD_SIZE) NeedAddressOverride = true; - } else if (MemoryOperand < 0) { - NeedAddressOverride = false; - } else if (STI.hasFeature(X86::Mode64Bit)) { - assert(!is16BitMemOperand(MI, MemoryOperand, STI)); - NeedAddressOverride = is32BitMemOperand(MI, MemoryOperand); - } else if (STI.hasFeature(X86::Mode32Bit)) { - assert(!is64BitMemOperand(MI, MemoryOperand)); - NeedAddressOverride = is16BitMemOperand(MI, MemoryOperand, STI); - } else { - assert(STI.hasFeature(X86::Mode16Bit)); - assert(!is64BitMemOperand(MI, MemoryOperand)); - NeedAddressOverride = !is16BitMemOperand(MI, MemoryOperand, STI); - } if (NeedAddressOverride) emitByte(0x67, OS); diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h --- a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h @@ -63,6 +63,28 @@ /// Returns true if this instruction has a LOCK prefix. bool hasLockPrefix(const MCInst &MI); +/// \param Op operand # of the memory operand. +/// +/// \returns true if the specified instruction has a 16-bit memory operand. +bool is16BitMemOperand(const MCInst &MI, unsigned Op, + const MCSubtargetInfo &STI); + +/// \param Op operand # of the memory operand. +/// +/// \returns true if the specified instruction has a 32-bit memory operand. +bool is32BitMemOperand(const MCInst &MI, unsigned Op); + +/// \param Op operand # of the memory operand. +/// +/// \returns true if the specified instruction has a 64-bit memory operand. +#ifndef NDEBUG +bool is64BitMemOperand(const MCInst &MI, unsigned Op); +#endif + +/// Returns true if this instruction needs an Address-Size override prefix. +bool needsAddressSizeOverride(const MCInst &MI, const MCSubtargetInfo &STI, + int MemoryOperand, uint64_t TSFlags); + /// Create a X86 MCSubtargetInfo instance. This is exposed so Asm parser, etc. /// do not need to go through TargetRegistry. MCSubtargetInfo *createX86MCSubtargetInfo(const Triple &TT, StringRef CPU, diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp --- a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp @@ -72,6 +72,71 @@ return MI.getFlags() & X86::IP_HAS_LOCK; } +template +bool isMemOperand(const MCInst &MI, unsigned Op) { + const MCOperand &Base = MI.getOperand(Op + X86::AddrBaseReg); + const MCOperand &Index = MI.getOperand(Op + X86::AddrIndexReg); + const MCRegisterClass &RC = X86MCRegisterClasses[RegClassID]; + + return (Base.isReg() && Base.getReg() != 0 && RC.contains(Base.getReg())) || + (Index.isReg() && Index.getReg() != 0 && RC.contains(Index.getReg())); +} + +bool X86_MC::is16BitMemOperand(const MCInst &MI, unsigned Op, + const MCSubtargetInfo &STI) { + const MCOperand &Base = MI.getOperand(Op + X86::AddrBaseReg); + const MCOperand &Index = MI.getOperand(Op + X86::AddrIndexReg); + + if (STI.hasFeature(X86::Mode16Bit) && Base.isReg() && Base.getReg() == 0 && + Index.isReg() && Index.getReg() == 0) + return true; + return isMemOperand(MI, Op); +} + +bool X86_MC::is32BitMemOperand(const MCInst &MI, unsigned Op) { + const MCOperand &Base = MI.getOperand(Op + X86::AddrBaseReg); + const MCOperand &Index = MI.getOperand(Op + X86::AddrIndexReg); + if (Base.isReg() && Base.getReg() == X86::EIP) { + assert(Index.isReg() && Index.getReg() == 0 && "Invalid eip-based address"); + return true; + } + if (Index.isReg() && Index.getReg() == X86::EIZ) + return true; + return isMemOperand(MI, Op); +} + +#ifndef NDEBUG +bool X86_MC::is64BitMemOperand(const MCInst &MI, unsigned Op) { + return isMemOperand(MI, Op); +} +#endif + +bool X86_MC::needsAddressSizeOverride(const MCInst &MI, + const MCSubtargetInfo &STI, + int MemoryOperand, uint64_t TSFlags) { + uint64_t AdSize = TSFlags & X86II::AdSizeMask; + if ((STI.hasFeature(X86::Mode16Bit) && AdSize == X86II::AdSize32) || + (STI.hasFeature(X86::Mode32Bit) && AdSize == X86II::AdSize16) || + (STI.hasFeature(X86::Mode64Bit) && AdSize == X86II::AdSize32)) + return true; + + // Determine where the memory operand starts, if present. + if (MemoryOperand < 0) + return false; + + if (STI.hasFeature(X86::Mode64Bit)) { + assert(!is16BitMemOperand(MI, MemoryOperand, STI)); + return is32BitMemOperand(MI, MemoryOperand); + } + if (STI.hasFeature(X86::Mode32Bit)) { + assert(!is64BitMemOperand(MI, MemoryOperand)); + return is16BitMemOperand(MI, MemoryOperand, STI); + } + assert(STI.hasFeature(X86::Mode16Bit)); + assert(!is64BitMemOperand(MI, MemoryOperand)); + return !is16BitMemOperand(MI, MemoryOperand, STI); +} + void X86_MC::initLLVMToSEHAndCVRegMapping(MCRegisterInfo *MRI) { // FIXME: TableGen these. for (unsigned Reg = X86::NoRegister + 1; Reg < X86::NUM_TARGET_REGS; ++Reg) { diff --git a/llvm/test/MC/Disassembler/X86/addr32.s b/llvm/test/MC/Disassembler/X86/addr32.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Disassembler/X86/addr32.s @@ -0,0 +1,5 @@ +# Check that we don't accidentally strip addr32 prefix + +# RUN: llvm-mc -disassemble %s -triple=x86_64 | FileCheck %s +# CHECK: addr32 callq +0x67 0xe8 0x00 0x00 0x00 0x00 diff --git a/llvm/test/MC/Disassembler/X86/prefixes.txt b/llvm/test/MC/Disassembler/X86/prefixes.txt --- a/llvm/test/MC/Disassembler/X86/prefixes.txt +++ b/llvm/test/MC/Disassembler/X86/prefixes.txt @@ -51,7 +51,7 @@ # CHECK: rep stosq %rax, %es:(%rdi) 0xf3 0x48 0xab -# CHECK: rep stosq %rax, %es:(%edi) +# CHECK: rep addr32 stosq %rax, %es:(%edi) 0xf3 0x67 0x48 0xab # CHECK: movl 32(%rbp), %eax diff --git a/llvm/test/MC/X86/addr16-32.s b/llvm/test/MC/X86/addr16-32.s --- a/llvm/test/MC/X86/addr16-32.s +++ b/llvm/test/MC/X86/addr16-32.s @@ -17,7 +17,7 @@ # CHECK: : # CHECK-NEXT: 6d insl %dx, %es:(%rdi) # CHECK-NEXT: 65 6f outsl %gs:(%rsi), %dx -# CHECK-NEXT: 67 6d insl %dx, %es:(%edi) -# CHECK-NEXT: 67 65 6f outsl %gs:(%esi), %dx -# CHECK-NEXT: 67 6d insl %dx, %es:(%edi) -# CHECK-NEXT: 67 65 6f outsl %gs:(%esi), %dx +# CHECK-NEXT: 67 6d addr32 insl %dx, %es:(%edi) +# CHECK-NEXT: 67 65 6f addr32 outsl %gs:(%esi), %dx +# CHECK-NEXT: 67 6d addr32 insl %dx, %es:(%edi) +# CHECK-NEXT: 67 65 6f addr32 outsl %gs:(%esi), %dx