diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index 5d6048616b6..f354c95c3a9 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -551,6 +551,7 @@ private: return 0; } + X86Operand *DefaultMemSIOperand(SMLoc Loc); X86Operand *ParseOperand(); X86Operand *ParseATTOperand(); X86Operand *ParseIntelOperand(); @@ -922,6 +923,25 @@ struct X86Operand : public MCParsedAsmOperand { !getMemIndexReg() && getMemScale() == 1; } + bool isSrcIdx() const { + return !getMemIndexReg() && getMemScale() == 1 && + (getMemBaseReg() == X86::RSI || getMemBaseReg() == X86::ESI || + getMemBaseReg() == X86::SI) && isa(getMemDisp()) && + cast(getMemDisp())->getValue() == 0; + } + bool isSrcIdx8() const { + return isMem8() && isSrcIdx(); + } + bool isSrcIdx16() const { + return isMem16() && isSrcIdx(); + } + bool isSrcIdx32() const { + return isMem32() && isSrcIdx(); + } + bool isSrcIdx64() const { + return isMem64() && isSrcIdx(); + } + bool isMemOffs8() const { return Kind == Memory && !getMemBaseReg() && !getMemIndexReg() && getMemScale() == 1 && (!Mem.Size || Mem.Size == 8); @@ -1014,6 +1034,12 @@ struct X86Operand : public MCParsedAsmOperand { Inst.addOperand(MCOperand::CreateExpr(getMemDisp())); } + void addSrcIdxOperands(MCInst &Inst, unsigned N) const { + assert((N == 2) && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getMemBaseReg())); + Inst.addOperand(MCOperand::CreateReg(getMemSegReg())); + } + void addMemOffsOperands(MCInst &Inst, unsigned N) const { assert((N == 2) && "Invalid number of operands!"); // Add as immediates when possible. @@ -1230,6 +1256,14 @@ bool X86AsmParser::ParseRegister(unsigned &RegNo, return false; } +X86Operand *X86AsmParser::DefaultMemSIOperand(SMLoc Loc) { + unsigned basereg = + is64BitMode() ? X86::RSI : (is32BitMode() ? X86::ESI : X86::SI); + const MCExpr *Disp = MCConstantExpr::Create(0, getContext()); + return X86Operand::CreateMem(/*SegReg=*/0, Disp, /*BaseReg=*/basereg, + /*IndexReg=*/0, /*Scale=*/1, Loc, Loc, 0); +} + X86Operand *X86AsmParser::ParseOperand() { if (isParsingIntelSyntax()) return ParseIntelOperand(); @@ -2278,36 +2312,14 @@ ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, delete &Op2; } } - // Transform "lods[bwl] %ds:(%esi),{%al,%ax,%eax,%rax}" into "lods[bwl]" - if (Name.startswith("lods") && Operands.size() == 3 && + // Transform "lods[bwlq]" into "lods[bwlq] ($SIREG)" for appropriate + // values of $SIREG according to the mode. It would be nice if this + // could be achieved with InstAlias in the tables. + if (Name.startswith("lods") && Operands.size() == 1 && (Name == "lods" || Name == "lodsb" || Name == "lodsw" || - Name == "lodsl" || (is64BitMode() && Name == "lodsq"))) { - X86Operand *Op1 = static_cast(Operands[1]); - X86Operand *Op2 = static_cast(Operands[2]); - if (isSrcOp(*Op1) && Op2->isReg()) { - const char *ins; - unsigned reg = Op2->getReg(); - bool isLods = Name == "lods"; - if (reg == X86::AL && (isLods || Name == "lodsb")) - ins = "lodsb"; - else if (reg == X86::AX && (isLods || Name == "lodsw")) - ins = "lodsw"; - else if (reg == X86::EAX && (isLods || Name == "lodsl")) - ins = "lodsl"; - else if (reg == X86::RAX && (isLods || Name == "lodsq")) - ins = "lodsq"; - else - ins = NULL; - if (ins != NULL) { - Operands.pop_back(); - Operands.pop_back(); - delete Op1; - delete Op2; - if (Name != ins) - static_cast(Operands[0])->setTokenValue(ins); - } - } - } + Name == "lodsl" || Name == "lodsd" || Name == "lodsq")) + Operands.push_back(DefaultMemSIOperand(NameLoc)); + // Transform "stos[bwl] {%al,%ax,%eax,%rax},%es:(%edi)" into "stos[bwl]" if (Name.startswith("stos") && Operands.size() == 3 && (Name == "stos" || Name == "stosb" || Name == "stosw" || diff --git a/lib/Target/X86/Disassembler/X86Disassembler.cpp b/lib/Target/X86/Disassembler/X86Disassembler.cpp index acfe88dd8f0..dae1345f708 100644 --- a/lib/Target/X86/Disassembler/X86Disassembler.cpp +++ b/lib/Target/X86/Disassembler/X86Disassembler.cpp @@ -233,6 +233,29 @@ static const uint8_t segmentRegnums[SEG_OVERRIDE_max] = { X86::GS }; +/// translateSrcIndex - Appends a source index operand to an MCInst. +/// +/// @param mcInst - The MCInst to append to. +/// @param operand - The operand, as stored in the descriptor table. +/// @param insn - The internal instruction. +static bool translateSrcIndex(MCInst &mcInst, InternalInstruction &insn) { + unsigned baseRegNo; + + if (insn.mode == MODE_64BIT) + baseRegNo = insn.prefixPresent[0x67] ? X86::ESI : X86::RSI; + else if (insn.mode == MODE_32BIT) + baseRegNo = insn.prefixPresent[0x67] ? X86::SI : X86::ESI; + else if (insn.mode == MODE_16BIT) + baseRegNo = insn.prefixPresent[0x67] ? X86::ESI : X86::SI; + MCOperand baseReg = MCOperand::CreateReg(baseRegNo); + mcInst.addOperand(baseReg); + + MCOperand segmentReg; + segmentReg = MCOperand::CreateReg(segmentRegnums[insn.segmentOverride]); + mcInst.addOperand(segmentReg); + return false; +} + /// translateImmediate - Appends an immediate operand to an MCInst. /// /// @param mcInst - The MCInst to append to. @@ -694,6 +717,8 @@ static bool translateOperand(MCInst &mcInst, const OperandSpecifier &operand, insn, Dis); return false; + case ENCODING_SI: + return translateSrcIndex(mcInst, insn); case ENCODING_RB: case ENCODING_RW: case ENCODING_RD: diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c index 48c16977133..8e591b8fdde 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c @@ -1682,6 +1682,7 @@ static int readOperands(struct InternalInstruction* insn) { for (index = 0; index < X86_MAX_OPERANDS; ++index) { switch (x86OperandSets[insn->spec->operands][index].encoding) { case ENCODING_NONE: + case ENCODING_SI: break; case ENCODING_REG: case ENCODING_RM: diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h index 1acaef1b947..c7fcb0ca200 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h @@ -409,7 +409,8 @@ struct ContextDecision { ENUM_ENTRY(ENCODING_Rv, "Register code of operand size added to the " \ "opcode byte") \ ENUM_ENTRY(ENCODING_DUP, "Duplicate of another operand; ID is encoded " \ - "in type") + "in type") \ + ENUM_ENTRY(ENCODING_SI, "Source index; encoded in OpSize/Adsize prefix") #define ENUM_ENTRY(n, d) n, typedef enum { @@ -460,6 +461,10 @@ struct ContextDecision { ENUM_ENTRY(TYPE_M16_16, "2+2-byte (BOUND)") \ ENUM_ENTRY(TYPE_M32_32, "4+4-byte (BOUND)") \ ENUM_ENTRY(TYPE_M16_64, "2+8-byte (LIDT, LGDT)") \ + ENUM_ENTRY(TYPE_SRCIDX8, "1-byte memory at source index") \ + ENUM_ENTRY(TYPE_SRCIDX16, "2-byte memory at source index") \ + ENUM_ENTRY(TYPE_SRCIDX32, "4-byte memory at source index") \ + ENUM_ENTRY(TYPE_SRCIDX64, "8-byte memory at source index") \ ENUM_ENTRY(TYPE_MOFFS8, "1-byte memory offset (relative to segment " \ "base)") \ ENUM_ENTRY(TYPE_MOFFS16, "2-byte") \ diff --git a/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp b/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp index 11a9ada41e5..4cd445765af 100644 --- a/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp +++ b/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp @@ -226,6 +226,25 @@ void X86ATTInstPrinter::printMemReference(const MCInst *MI, unsigned Op, O << markup(">"); } +void X86ATTInstPrinter::printSrcIdx(const MCInst *MI, unsigned Op, + raw_ostream &O) { + const MCOperand &SegReg = MI->getOperand(Op+1); + + O << markup(""); +} + void X86ATTInstPrinter::printMemOffset(const MCInst *MI, unsigned Op, raw_ostream &O) { const MCOperand &DispSpec = MI->getOperand(Op); diff --git a/lib/Target/X86/InstPrinter/X86ATTInstPrinter.h b/lib/Target/X86/InstPrinter/X86ATTInstPrinter.h index 4dc4fe6eabd..8c7c838ae47 100644 --- a/lib/Target/X86/InstPrinter/X86ATTInstPrinter.h +++ b/lib/Target/X86/InstPrinter/X86ATTInstPrinter.h @@ -42,6 +42,7 @@ public: void printSSECC(const MCInst *MI, unsigned Op, raw_ostream &OS); void printAVXCC(const MCInst *MI, unsigned Op, raw_ostream &OS); void printPCRelImm(const MCInst *MI, unsigned OpNo, raw_ostream &OS); + void printSrcIdx(const MCInst *MI, unsigned OpNo, raw_ostream &OS); void printMemOffset(const MCInst *MI, unsigned OpNo, raw_ostream &OS); void printRoundingControl(const MCInst *MI, unsigned Op, raw_ostream &OS); @@ -89,6 +90,18 @@ public: printMemReference(MI, OpNo, O); } + void printSrcIdx8(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + printSrcIdx(MI, OpNo, O); + } + void printSrcIdx16(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + printSrcIdx(MI, OpNo, O); + } + void printSrcIdx32(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + printSrcIdx(MI, OpNo, O); + } + void printSrcIdx64(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + printSrcIdx(MI, OpNo, O); + } void printMemOffs8(const MCInst *MI, unsigned OpNo, raw_ostream &O) { printMemOffset(MI, OpNo, O); } diff --git a/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp b/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp index 59634f9ad85..8ea070b39ff 100644 --- a/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp +++ b/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp @@ -212,6 +212,20 @@ void X86IntelInstPrinter::printMemReference(const MCInst *MI, unsigned Op, O << ']'; } +void X86IntelInstPrinter::printSrcIdx(const MCInst *MI, unsigned Op, + raw_ostream &O) { + const MCOperand &SegReg = MI->getOperand(Op+1); + + // If this has a segment register, print it. + if (SegReg.getReg()) { + printOperand(MI, Op+1, O); + O << ':'; + } + O << '['; + printOperand(MI, Op, O); + O << ']'; +} + void X86IntelInstPrinter::printMemOffset(const MCInst *MI, unsigned Op, raw_ostream &O) { const MCOperand &DispSpec = MI->getOperand(Op); diff --git a/lib/Target/X86/InstPrinter/X86IntelInstPrinter.h b/lib/Target/X86/InstPrinter/X86IntelInstPrinter.h index 90d4e397849..067df8129ab 100644 --- a/lib/Target/X86/InstPrinter/X86IntelInstPrinter.h +++ b/lib/Target/X86/InstPrinter/X86IntelInstPrinter.h @@ -40,6 +40,7 @@ public: void printAVXCC(const MCInst *MI, unsigned Op, raw_ostream &O); void printPCRelImm(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printMemOffset(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printSrcIdx(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printRoundingControl(const MCInst *MI, unsigned Op, raw_ostream &OS); void printopaquemem(const MCInst *MI, unsigned OpNo, raw_ostream &O) { @@ -100,6 +101,23 @@ public: printMemReference(MI, OpNo, O); } + + void printSrcIdx8(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + O << "byte ptr "; + printSrcIdx(MI, OpNo, O); + } + void printSrcIdx16(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + O << "word ptr "; + printSrcIdx(MI, OpNo, O); + } + void printSrcIdx32(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + O << "dword ptr "; + printSrcIdx(MI, OpNo, O); + } + void printSrcIdx64(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + O << "qword ptr "; + printSrcIdx(MI, OpNo, O); + } void printMemOffs8(const MCInst *MI, unsigned OpNo, raw_ostream &O) { O << "byte ptr "; printMemOffset(MI, OpNo, O); diff --git a/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/lib/Target/X86/MCTargetDesc/X86BaseInfo.h index b25a35e321c..1ca0bd656d5 100644 --- a/lib/Target/X86/MCTargetDesc/X86BaseInfo.h +++ b/lib/Target/X86/MCTargetDesc/X86BaseInfo.h @@ -259,6 +259,10 @@ namespace X86II { /// memory offset as an immediate with a possible segment override. RawFrmMemOffs = 7, + /// RawFrmSrc - This form is for instructions that use the source index + /// register SI/ESI/RSI with a possible segment override. + RawFrmSrc = 8, + /// MRM[0-7][rm] - These forms are used to represent instructions that use /// a Mod/RM byte, and use the middle field to hold extended opcode /// information. In the intel manual these are represented as /0, /1, ... @@ -612,6 +616,7 @@ namespace X86II { case X86II::RawFrmImm8: case X86II::RawFrmImm16: case X86II::RawFrmMemOffs: + case X86II::RawFrmSrc: return -1; case X86II::MRMDestMem: return 0; diff --git a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp index 813691b09e4..ac72fce032f 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -1317,6 +1317,19 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, llvm_unreachable("Unknown FormMask value in X86MCCodeEmitter!"); case X86II::Pseudo: llvm_unreachable("Pseudo instruction shouldn't be emitted"); + case X86II::RawFrmSrc: { + unsigned siReg = MI.getOperand(0).getReg(); + // Emit segment override opcode prefix as needed (not for %ds). + if (MI.getOperand(1).getReg() != X86::DS) + EmitSegmentOverridePrefix(CurByte, 1, MI, OS); + // Emit OpSize prefix as needed. + if ((!is32BitMode() && siReg == X86::ESI) || + (is32BitMode() && siReg == X86::SI)) + EmitByte(0x67, CurByte, OS); + CurOp += 2; // Consume operands. + EmitByte(BaseOpcode, CurByte, OS); + break; + } case X86II::RawFrm: EmitByte(BaseOpcode, CurByte, OS); break; diff --git a/lib/Target/X86/X86InstrFormats.td b/lib/Target/X86/X86InstrFormats.td index eed361958f6..a239d1f5234 100644 --- a/lib/Target/X86/X86InstrFormats.td +++ b/lib/Target/X86/X86InstrFormats.td @@ -22,6 +22,7 @@ def Pseudo : Format<0>; def RawFrm : Format<1>; def AddRegFrm : Format<2>; def MRMDestReg : Format<3>; def MRMDestMem : Format<4>; def MRMSrcReg : Format<5>; def MRMSrcMem : Format<6>; def RawFrmMemOffs : Format<7>; +def RawFrmSrc : Format<8>; def MRM0r : Format<16>; def MRM1r : Format<17>; def MRM2r : Format<18>; def MRM3r : Format<19>; def MRM4r : Format<20>; def MRM5r : Format<21>; def MRM6r : Format<22>; def MRM7r : Format<23>; diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 486435d35d5..d3e102747e3 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -445,6 +445,26 @@ def brtarget8 : Operand; } +def X86SrcIdx8Operand : AsmOperandClass { + let Name = "SrcIdx8"; + let RenderMethod = "addSrcIdxOperands"; + let SuperClasses = [X86Mem8AsmOperand]; +} +def X86SrcIdx16Operand : AsmOperandClass { + let Name = "SrcIdx16"; + let RenderMethod = "addSrcIdxOperands"; + let SuperClasses = [X86Mem16AsmOperand]; +} +def X86SrcIdx32Operand : AsmOperandClass { + let Name = "SrcIdx32"; + let RenderMethod = "addSrcIdxOperands"; + let SuperClasses = [X86Mem32AsmOperand]; +} +def X86SrcIdx64Operand : AsmOperandClass { + let Name = "SrcIdx64"; + let RenderMethod = "addSrcIdxOperands"; + let SuperClasses = [X86Mem64AsmOperand]; +} def X86MemOffs8AsmOperand : AsmOperandClass { let Name = "MemOffs8"; let RenderMethod = "addMemOffsOperands"; @@ -465,8 +485,23 @@ def X86MemOffs64AsmOperand : AsmOperandClass { let RenderMethod = "addMemOffsOperands"; let SuperClasses = [X86Mem64AsmOperand]; } - let OperandType = "OPERAND_MEMORY" in { +def srcidx8 : Operand { + let ParserMatchClass = X86SrcIdx8Operand; + let MIOperandInfo = (ops ptr_rc, i8imm); + let PrintMethod = "printSrcIdx8"; } +def srcidx16 : Operand { + let ParserMatchClass = X86SrcIdx16Operand; + let MIOperandInfo = (ops ptr_rc, i8imm); + let PrintMethod = "printSrcIdx16"; } +def srcidx32 : Operand { + let ParserMatchClass = X86SrcIdx32Operand; + let MIOperandInfo = (ops ptr_rc, i8imm); + let PrintMethod = "printSrcIdx32"; } +def srcidx64 : Operand { + let ParserMatchClass = X86SrcIdx64Operand; + let MIOperandInfo = (ops ptr_rc, i8imm); + let PrintMethod = "printSrcIdx64"; } def offset8 : Operand { let ParserMatchClass = X86MemOffs8AsmOperand; let MIOperandInfo = (ops i64imm, i8imm); @@ -1676,10 +1711,14 @@ def REPNE_PREFIX : I<0xF2, RawFrm, (outs), (ins), "repne", []>; // String manipulation instructions let SchedRW = [WriteMicrocoded] in { -def LODSB : I<0xAC, RawFrm, (outs), (ins), "lodsb", [], IIC_LODS>; -def LODSW : I<0xAD, RawFrm, (outs), (ins), "lodsw", [], IIC_LODS>, OpSize; -def LODSL : I<0xAD, RawFrm, (outs), (ins), "lods{l|d}", [], IIC_LODS>, OpSize16; -def LODSQ : RI<0xAD, RawFrm, (outs), (ins), "lodsq", [], IIC_LODS>; +def LODSB : I<0xAC, RawFrmSrc, (outs), (ins srcidx8:$src), + "lodsb\t{$src, %al|al, $src}", [], IIC_LODS>; +def LODSW : I<0xAD, RawFrmSrc, (outs), (ins srcidx16:$src), + "lodsw\t{$src, %ax|ax, $src}", [], IIC_LODS>, OpSize; +def LODSL : I<0xAD, RawFrmSrc, (outs), (ins srcidx32:$src), + "lods{l|d}\t{$src, %eax|eax, $src}", [], IIC_LODS>, OpSize16; +def LODSQ : RI<0xAD, RawFrmSrc, (outs), (ins srcidx64:$src), + "lodsq\t{$src, %rax|rax, $src}", [], IIC_LODS>; } let SchedRW = [WriteSystem] in { @@ -2329,6 +2368,18 @@ def : InstAlias<"clrw $reg", (XOR16rr GR16:$reg, GR16:$reg), 0>; def : InstAlias<"clrl $reg", (XOR32rr GR32:$reg, GR32:$reg), 0>; def : InstAlias<"clrq $reg", (XOR64rr GR64:$reg, GR64:$reg), 0>; +// lods aliases. Accept the destination being omitted because it's implicit +// in the mnemonic, or the mnemonic suffix being omitted because it's implicit +// in the destination. +def : InstAlias<"lodsb $src", (LODSB srcidx8:$src), 0>; +def : InstAlias<"lodsw $src", (LODSW srcidx16:$src), 0>; +def : InstAlias<"lods{l|d} $src", (LODSL srcidx32:$src), 0>; +def : InstAlias<"lodsq $src", (LODSQ srcidx64:$src), 0>, Requires<[In64BitMode]>; +def : InstAlias<"lods {$src, %al|al, $src}", (LODSB srcidx8:$src), 0>; +def : InstAlias<"lods {$src, %ax|ax, $src}", (LODSW srcidx16:$src), 0>; +def : InstAlias<"lods {$src, %eax|eax, $src}", (LODSL srcidx32:$src), 0>; +def : InstAlias<"lods {$src, %rax|rax, $src}", (LODSQ srcidx64:$src), 0>, Requires<[In64BitMode]>; + // div and idiv aliases for explicit A register. def : InstAlias<"div{b}\t{$src, %al|al, $src}", (DIV8r GR8 :$src)>; def : InstAlias<"div{w}\t{$src, %ax|ax, $src}", (DIV16r GR16:$src)>; diff --git a/test/MC/X86/index-operations.s b/test/MC/X86/index-operations.s new file mode 100644 index 00000000000..a5dd88b1d48 --- /dev/null +++ b/test/MC/X86/index-operations.s @@ -0,0 +1,46 @@ +// RUN: not llvm-mc -triple x86_64-unknown-unknown --show-encoding %s 2> %t.err | FileCheck --check-prefix=64 %s +// RUN: FileCheck --check-prefix=ERR64 < %t.err %s +// RUN: not llvm-mc -triple i386-unknown-unknown --show-encoding %s 2> %t.err | FileCheck --check-prefix=32 %s +// RUN: FileCheck --check-prefix=ERR32 < %t.err %s +// RUN: not llvm-mc -triple i386-unknown-unknown-code16 --show-encoding %s 2> %t.err | FileCheck --check-prefix=16 %s +// RUN: FileCheck --check-prefix=ERR16 < %t.err %s + +lodsb +// 64: lodsb (%rsi), %al # encoding: [0xac] +// 32: lodsb (%esi), %al # encoding: [0xac] +// 16: lodsb (%si), %al # encoding: [0xac] + +lodsb (%rsi), %al +// 64: lodsb (%rsi), %al # encoding: [0xac] +// ERR32: 64-bit +// ERR16: 64-bit + +lodsb (%esi), %al +// 64: lodsb (%esi), %al # encoding: [0x67,0xac] +// 32: lodsb (%esi), %al # encoding: [0xac] +// 16: lodsb (%esi), %al # encoding: [0x67,0xac] + +lodsb (%si), %al +// ERR64: invalid 16-bit base register +// 32: lodsb (%si), %al # encoding: [0x67,0xac] +// 16: lodsb (%si), %al # encoding: [0xac] + +lodsl %gs:(%esi) +// 64: lodsl %gs:(%esi), %eax # encoding: [0x65,0x67,0xad] +// 32: lodsl %gs:(%esi), %eax # encoding: [0x65,0xad] +// 16: lodsl %gs:(%esi), %eax # encoding: [0x66,0x65,0x67,0xad] + +lodsl (%edi), %eax +// ERR64: invalid operand +// ERR32: invalid operand +// ERR16: invalid operand + +lodsl 44(%edi), %eax +// ERR64: invalid operand +// ERR32: invalid operand +// ERR16: invalid operand + +lods (%esi), %ax +// 64: lodsw (%esi), %ax # encoding: [0x66,0x67,0xad] +// 32: lodsw (%esi), %ax # encoding: [0x66,0xad] +// 16: lodsw (%esi), %ax # encoding: [0x67,0xad] diff --git a/test/MC/X86/x86-16.s b/test/MC/X86/x86-16.s index 41d068e3d02..4b54a027a88 100644 --- a/test/MC/X86/x86-16.s +++ b/test/MC/X86/x86-16.s @@ -845,7 +845,7 @@ pshufw $90, %mm4, %mm0 movsl %ds:(%si), %es:(%di) movsl (%si), %es:(%di) -// CHECK: lodsb # encoding: [0xac] +// CHECK: lodsb (%si), %al # encoding: [0xac] // CHECK: lodsb // CHECK: lodsb // CHECK: lodsb @@ -856,7 +856,7 @@ pshufw $90, %mm4, %mm0 lods %ds:(%si), %al lods (%si), %al -// CHECK: lodsw # encoding: [0xad] +// CHECK: lodsw (%si), %ax # encoding: [0xad] // CHECK: lodsw // CHECK: lodsw // CHECK: lodsw @@ -867,7 +867,7 @@ pshufw $90, %mm4, %mm0 lods %ds:(%si), %ax lods (%si), %ax -// CHECK: lodsl # encoding: [0x66,0xad] +// CHECK: lodsl (%si), %eax # encoding: [0x66,0xad] // CHECK: lodsl // CHECK: lodsl // CHECK: lodsl diff --git a/test/MC/X86/x86-32.s b/test/MC/X86/x86-32.s index 140c05af6bc..29be52e35c4 100644 --- a/test/MC/X86/x86-32.s +++ b/test/MC/X86/x86-32.s @@ -921,7 +921,7 @@ pshufw $90, %mm4, %mm0 movsl %ds:(%esi), %es:(%edi) movsl (%esi), %es:(%edi) -// CHECK: lodsb # encoding: [0xac] +// CHECK: lodsb (%esi), %al # encoding: [0xac] // CHECK: lodsb // CHECK: lodsb // CHECK: lodsb @@ -932,7 +932,7 @@ pshufw $90, %mm4, %mm0 lods %ds:(%esi), %al lods (%esi), %al -// CHECK: lodsw # encoding: [0x66,0xad] +// CHECK: lodsw (%esi), %ax # encoding: [0x66,0xad] // CHECK: lodsw // CHECK: lodsw // CHECK: lodsw @@ -943,7 +943,7 @@ pshufw $90, %mm4, %mm0 lods %ds:(%esi), %ax lods (%esi), %ax -// CHECK: lodsl # encoding: [0xad] +// CHECK: lodsl (%esi), %eax # encoding: [0xad] // CHECK: lodsl // CHECK: lodsl // CHECK: lodsl diff --git a/test/MC/X86/x86-64.s b/test/MC/X86/x86-64.s index 28035c076cb..ef798d7f080 100644 --- a/test/MC/X86/x86-64.s +++ b/test/MC/X86/x86-64.s @@ -1116,7 +1116,7 @@ xsetbv // CHECK: xsetbv # encoding: [0x0f,0x01,0xd1] movsq %ds:(%rsi), %es:(%rdi) movsq (%rsi), %es:(%rdi) -// CHECK: lodsb # encoding: [0xac] +// CHECK: lodsb (%rsi), %al # encoding: [0xac] // CHECK: lodsb // CHECK: lodsb // CHECK: lodsb @@ -1127,7 +1127,7 @@ xsetbv // CHECK: xsetbv # encoding: [0x0f,0x01,0xd1] lods %ds:(%rsi), %al lods (%rsi), %al -// CHECK: lodsw # encoding: [0x66,0xad] +// CHECK: lodsw (%rsi), %ax # encoding: [0x66,0xad] // CHECK: lodsw // CHECK: lodsw // CHECK: lodsw @@ -1138,7 +1138,7 @@ xsetbv // CHECK: xsetbv # encoding: [0x0f,0x01,0xd1] lods %ds:(%rsi), %ax lods (%rsi), %ax -// CHECK: lodsl # encoding: [0xad] +// CHECK: lodsl (%rsi), %eax # encoding: [0xad] // CHECK: lodsl // CHECK: lodsl // CHECK: lodsl @@ -1149,7 +1149,7 @@ xsetbv // CHECK: xsetbv # encoding: [0x0f,0x01,0xd1] lods %ds:(%rsi), %eax lods (%rsi), %eax -// CHECK: lodsq # encoding: [0x48,0xad] +// CHECK: lodsq (%rsi), %rax # encoding: [0x48,0xad] // CHECK: lodsq // CHECK: lodsq // CHECK: lodsq diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index c09abefeef6..1530c42f76a 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -60,6 +60,7 @@ namespace X86Local { MRMSrcReg = 5, MRMSrcMem = 6, RawFrmMemOffs = 7, + RawFrmSrc = 8, MRM0r = 16, MRM1r = 17, MRM2r = 18, MRM3r = 19, MRM4r = 20, MRM5r = 21, MRM6r = 22, MRM7r = 23, MRM0m = 24, MRM1m = 25, MRM2m = 26, MRM3m = 27, @@ -630,6 +631,9 @@ void RecognizableInstr::emitInstructionSpecifier() { switch (Form) { default: llvm_unreachable("Unhandled form"); + case X86Local::RawFrmSrc: + HANDLE_OPERAND(relocation); + return; case X86Local::RawFrm: // Operand 1 (optional) is an address or immediate. // Operand 2 (optional) is an immediate. @@ -1262,6 +1266,10 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("SEGMENT_REG", TYPE_SEGMENTREG) TYPE("DEBUG_REG", TYPE_DEBUGREG) TYPE("CONTROL_REG", TYPE_CONTROLREG) + TYPE("srcidx8", TYPE_SRCIDX8) + TYPE("srcidx16", TYPE_SRCIDX16) + TYPE("srcidx32", TYPE_SRCIDX32) + TYPE("srcidx64", TYPE_SRCIDX64) TYPE("offset8", TYPE_MOFFS8) TYPE("offset16", TYPE_MOFFS16) TYPE("offset32", TYPE_MOFFS32) @@ -1474,6 +1482,10 @@ OperandEncoding RecognizableInstr::relocationEncodingFromString ENCODING("offset16", ENCODING_Ia) ENCODING("offset32", ENCODING_Ia) ENCODING("offset64", ENCODING_Ia) + ENCODING("srcidx8", ENCODING_SI) + ENCODING("srcidx16", ENCODING_SI) + ENCODING("srcidx32", ENCODING_SI) + ENCODING("srcidx64", ENCODING_SI) errs() << "Unhandled relocation encoding " << s << "\n"; llvm_unreachable("Unhandled relocation encoding"); }