From ccbfd5b18a79a07229f11af478843eae16ac9b26 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 22 Jan 2014 15:08:21 +0000 Subject: [PATCH] [x86] Allow address-size overrides for STOS[BWLQ] (PR9385) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199804 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/AsmParser/X86AsmParser.cpp | 68 +++++++++++-------- .../X86/Disassembler/X86Disassembler.cpp | 22 ++++++ .../X86/Disassembler/X86DisassemblerDecoder.c | 1 + .../X86DisassemblerDecoderCommon.h | 7 +- .../X86/InstPrinter/X86ATTInstPrinter.cpp | 11 +++ .../X86/InstPrinter/X86ATTInstPrinter.h | 13 ++++ .../X86/InstPrinter/X86IntelInstPrinter.cpp | 8 +++ .../X86/InstPrinter/X86IntelInstPrinter.h | 17 +++++ lib/Target/X86/MCTargetDesc/X86BaseInfo.h | 5 ++ .../X86/MCTargetDesc/X86MCCodeEmitter.cpp | 10 +++ lib/Target/X86/X86InstrFormats.td | 2 +- lib/Target/X86/X86InstrInfo.td | 60 ++++++++++++++-- test/MC/X86/index-operations.s | 30 ++++++++ test/MC/X86/x86-16.s | 6 +- test/MC/X86/x86-32.s | 6 +- test/MC/X86/x86-64.s | 8 +-- utils/TableGen/X86RecognizableInstr.cpp | 12 ++++ 17 files changed, 241 insertions(+), 45 deletions(-) diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index f354c95c3a9..503ae9b6f51 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -552,6 +552,7 @@ private: } X86Operand *DefaultMemSIOperand(SMLoc Loc); + X86Operand *DefaultMemDIOperand(SMLoc Loc); X86Operand *ParseOperand(); X86Operand *ParseATTOperand(); X86Operand *ParseIntelOperand(); @@ -942,6 +943,26 @@ struct X86Operand : public MCParsedAsmOperand { return isMem64() && isSrcIdx(); } + bool isDstIdx() const { + return !getMemIndexReg() && getMemScale() == 1 && + (getMemSegReg() == 0 || getMemSegReg() == X86::ES) && + (getMemBaseReg() == X86::RDI || getMemBaseReg() == X86::EDI || + getMemBaseReg() == X86::DI) && isa(getMemDisp()) && + cast(getMemDisp())->getValue() == 0; + } + bool isDstIdx8() const { + return isMem8() && isDstIdx(); + } + bool isDstIdx16() const { + return isMem16() && isDstIdx(); + } + bool isDstIdx32() const { + return isMem32() && isDstIdx(); + } + bool isDstIdx64() const { + return isMem64() && isDstIdx(); + } + bool isMemOffs8() const { return Kind == Memory && !getMemBaseReg() && !getMemIndexReg() && getMemScale() == 1 && (!Mem.Size || Mem.Size == 8); @@ -1039,6 +1060,10 @@ struct X86Operand : public MCParsedAsmOperand { Inst.addOperand(MCOperand::CreateReg(getMemBaseReg())); Inst.addOperand(MCOperand::CreateReg(getMemSegReg())); } + void addDstIdxOperands(MCInst &Inst, unsigned N) const { + assert((N == 1) && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getMemBaseReg())); + } void addMemOffsOperands(MCInst &Inst, unsigned N) const { assert((N == 2) && "Invalid number of operands!"); @@ -1264,6 +1289,14 @@ X86Operand *X86AsmParser::DefaultMemSIOperand(SMLoc Loc) { /*IndexReg=*/0, /*Scale=*/1, Loc, Loc, 0); } +X86Operand *X86AsmParser::DefaultMemDIOperand(SMLoc Loc) { + unsigned basereg = + is64BitMode() ? X86::RDI : (is32BitMode() ? X86::EDI : X86::DI); + 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(); @@ -2320,36 +2353,13 @@ ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, 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 && + // Transform "stos[bwlq]" into "stos[bwlq] ($DIREG)" for appropriate + // values of $DIREG according to the mode. It would be nice if this + // could be achieved with InstAlias in the tables. + if (Name.startswith("stos") && Operands.size() == 1 && (Name == "stos" || Name == "stosb" || Name == "stosw" || - Name == "stosl" || (is64BitMode() && Name == "stosq"))) { - X86Operand *Op1 = static_cast(Operands[1]); - X86Operand *Op2 = static_cast(Operands[2]); - if (isDstOp(*Op2) && Op1->isReg()) { - const char *ins; - unsigned reg = Op1->getReg(); - bool isStos = Name == "stos"; - if (reg == X86::AL && (isStos || Name == "stosb")) - ins = "stosb"; - else if (reg == X86::AX && (isStos || Name == "stosw")) - ins = "stosw"; - else if (reg == X86::EAX && (isStos || Name == "stosl")) - ins = "stosl"; - else if (reg == X86::RAX && (isStos || Name == "stosq")) - ins = "stosq"; - 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 == "stosl" || Name == "stosd" || Name == "stosq")) + Operands.push_back(DefaultMemDIOperand(NameLoc)); // FIXME: Hack to handle recognize s{hr,ar,hl} $1, . Canonicalize to // "shift ". diff --git a/lib/Target/X86/Disassembler/X86Disassembler.cpp b/lib/Target/X86/Disassembler/X86Disassembler.cpp index dae1345f708..440219dc9af 100644 --- a/lib/Target/X86/Disassembler/X86Disassembler.cpp +++ b/lib/Target/X86/Disassembler/X86Disassembler.cpp @@ -256,6 +256,26 @@ static bool translateSrcIndex(MCInst &mcInst, InternalInstruction &insn) { return false; } +/// translateDstIndex - Appends a destination 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 translateDstIndex(MCInst &mcInst, InternalInstruction &insn) { + unsigned baseRegNo; + + if (insn.mode == MODE_64BIT) + baseRegNo = insn.prefixPresent[0x67] ? X86::EDI : X86::RDI; + else if (insn.mode == MODE_32BIT) + baseRegNo = insn.prefixPresent[0x67] ? X86::DI : X86::EDI; + else if (insn.mode == MODE_16BIT) + baseRegNo = insn.prefixPresent[0x67] ? X86::EDI : X86::DI; + MCOperand baseReg = MCOperand::CreateReg(baseRegNo); + mcInst.addOperand(baseReg); + return false; +} + /// translateImmediate - Appends an immediate operand to an MCInst. /// /// @param mcInst - The MCInst to append to. @@ -719,6 +739,8 @@ static bool translateOperand(MCInst &mcInst, const OperandSpecifier &operand, return false; case ENCODING_SI: return translateSrcIndex(mcInst, insn); + case ENCODING_DI: + return translateDstIndex(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 8e591b8fdde..85f74358d95 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c @@ -1683,6 +1683,7 @@ static int readOperands(struct InternalInstruction* insn) { switch (x86OperandSets[insn->spec->operands][index].encoding) { case ENCODING_NONE: case ENCODING_SI: + case ENCODING_DI: break; case ENCODING_REG: case ENCODING_RM: diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h index c7fcb0ca200..a5c26d0b711 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h @@ -410,7 +410,8 @@ struct ContextDecision { "opcode byte") \ ENUM_ENTRY(ENCODING_DUP, "Duplicate of another operand; ID is encoded " \ "in type") \ - ENUM_ENTRY(ENCODING_SI, "Source index; encoded in OpSize/Adsize prefix") + ENUM_ENTRY(ENCODING_SI, "Source index; encoded in OpSize/Adsize prefix") \ + ENUM_ENTRY(ENCODING_DI, "Destination index; encoded in prefixes") #define ENUM_ENTRY(n, d) n, typedef enum { @@ -465,6 +466,10 @@ struct ContextDecision { 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_DSTIDX8, "1-byte memory at destination index") \ + ENUM_ENTRY(TYPE_DSTIDX16, "2-byte memory at destination index") \ + ENUM_ENTRY(TYPE_DSTIDX32, "4-byte memory at destination index") \ + ENUM_ENTRY(TYPE_DSTIDX64, "8-byte memory at destination 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 4cd445765af..4be686aa7a7 100644 --- a/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp +++ b/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp @@ -245,6 +245,17 @@ void X86ATTInstPrinter::printSrcIdx(const MCInst *MI, unsigned Op, O << markup(">"); } +void X86ATTInstPrinter::printDstIdx(const MCInst *MI, unsigned Op, + raw_ostream &O) { + 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 8c7c838ae47..18235601364 100644 --- a/lib/Target/X86/InstPrinter/X86ATTInstPrinter.h +++ b/lib/Target/X86/InstPrinter/X86ATTInstPrinter.h @@ -43,6 +43,7 @@ public: 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 printDstIdx(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); @@ -102,6 +103,18 @@ public: void printSrcIdx64(const MCInst *MI, unsigned OpNo, raw_ostream &O) { printSrcIdx(MI, OpNo, O); } + void printDstIdx8(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + printDstIdx(MI, OpNo, O); + } + void printDstIdx16(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + printDstIdx(MI, OpNo, O); + } + void printDstIdx32(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + printDstIdx(MI, OpNo, O); + } + void printDstIdx64(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + printDstIdx(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 8ea070b39ff..e6d21fb7525 100644 --- a/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp +++ b/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp @@ -226,6 +226,14 @@ void X86IntelInstPrinter::printSrcIdx(const MCInst *MI, unsigned Op, O << ']'; } +void X86IntelInstPrinter::printDstIdx(const MCInst *MI, unsigned Op, + raw_ostream &O) { + // DI accesses are always ES-based. + O << "es:["; + 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 067df8129ab..47b65b2b365 100644 --- a/lib/Target/X86/InstPrinter/X86IntelInstPrinter.h +++ b/lib/Target/X86/InstPrinter/X86IntelInstPrinter.h @@ -41,6 +41,7 @@ public: 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 printDstIdx(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) { @@ -118,6 +119,22 @@ public: O << "qword ptr "; printSrcIdx(MI, OpNo, O); } + void printDstIdx8(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + O << "byte ptr "; + printDstIdx(MI, OpNo, O); + } + void printDstIdx16(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + O << "word ptr "; + printDstIdx(MI, OpNo, O); + } + void printDstIdx32(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + O << "dword ptr "; + printDstIdx(MI, OpNo, O); + } + void printDstIdx64(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + O << "qword ptr "; + printDstIdx(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 1ca0bd656d5..69e74b86591 100644 --- a/lib/Target/X86/MCTargetDesc/X86BaseInfo.h +++ b/lib/Target/X86/MCTargetDesc/X86BaseInfo.h @@ -263,6 +263,10 @@ namespace X86II { /// register SI/ESI/RSI with a possible segment override. RawFrmSrc = 8, + /// RawFrmDst - This form is for instructions that use the destination index + /// register DI/EDI/ESI. + RawFrmDst = 9, + /// 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, ... @@ -617,6 +621,7 @@ namespace X86II { case X86II::RawFrmImm16: case X86II::RawFrmMemOffs: case X86II::RawFrmSrc: + case X86II::RawFrmDst: return -1; case X86II::MRMDestMem: return 0; diff --git a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp index ac72fce032f..0f1ab6d473a 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -1330,6 +1330,16 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, EmitByte(BaseOpcode, CurByte, OS); break; } + case X86II::RawFrmDst: { + unsigned siReg = MI.getOperand(0).getReg(); + // Emit OpSize prefix as needed. + if ((!is32BitMode() && siReg == X86::EDI) || + (is32BitMode() && siReg == X86::DI)) + EmitByte(0x67, CurByte, OS); + ++CurOp; // Consume operand. + 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 a239d1f5234..0ad8f57e0be 100644 --- a/lib/Target/X86/X86InstrFormats.td +++ b/lib/Target/X86/X86InstrFormats.td @@ -22,7 +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 RawFrmSrc : Format<8>; def RawFrmDst : Format<9>; 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 d3e102747e3..c7e44232971 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -465,6 +465,26 @@ def X86SrcIdx64Operand : AsmOperandClass { let RenderMethod = "addSrcIdxOperands"; let SuperClasses = [X86Mem64AsmOperand]; } +def X86DstIdx8Operand : AsmOperandClass { + let Name = "DstIdx8"; + let RenderMethod = "addDstIdxOperands"; + let SuperClasses = [X86Mem8AsmOperand]; +} +def X86DstIdx16Operand : AsmOperandClass { + let Name = "DstIdx16"; + let RenderMethod = "addDstIdxOperands"; + let SuperClasses = [X86Mem16AsmOperand]; +} +def X86DstIdx32Operand : AsmOperandClass { + let Name = "DstIdx32"; + let RenderMethod = "addDstIdxOperands"; + let SuperClasses = [X86Mem32AsmOperand]; +} +def X86DstIdx64Operand : AsmOperandClass { + let Name = "DstIdx64"; + let RenderMethod = "addDstIdxOperands"; + let SuperClasses = [X86Mem64AsmOperand]; +} def X86MemOffs8AsmOperand : AsmOperandClass { let Name = "MemOffs8"; let RenderMethod = "addMemOffsOperands"; @@ -502,6 +522,22 @@ def srcidx64 : Operand { let ParserMatchClass = X86SrcIdx64Operand; let MIOperandInfo = (ops ptr_rc, i8imm); let PrintMethod = "printSrcIdx64"; } +def dstidx8 : Operand { + let ParserMatchClass = X86DstIdx8Operand; + let MIOperandInfo = (ops ptr_rc); + let PrintMethod = "printDstIdx8"; } +def dstidx16 : Operand { + let ParserMatchClass = X86DstIdx16Operand; + let MIOperandInfo = (ops ptr_rc); + let PrintMethod = "printDstIdx16"; } +def dstidx32 : Operand { + let ParserMatchClass = X86DstIdx32Operand; + let MIOperandInfo = (ops ptr_rc); + let PrintMethod = "printDstIdx32"; } +def dstidx64 : Operand { + let ParserMatchClass = X86DstIdx64Operand; + let MIOperandInfo = (ops ptr_rc); + let PrintMethod = "printDstIdx64"; } def offset8 : Operand { let ParserMatchClass = X86MemOffs8AsmOperand; let MIOperandInfo = (ops i64imm, i8imm); @@ -1109,13 +1145,17 @@ def MOVSQ : RI<0xA5, RawFrm, (outs), (ins), "movsq", [], IIC_MOVS>; // These uses the DF flag in the EFLAGS register to inc or dec EDI and ESI let Defs = [EDI], Uses = [AL,EDI,EFLAGS] in -def STOSB : I<0xAA, RawFrm, (outs), (ins), "stosb", [], IIC_STOS>; +def STOSB : I<0xAA, RawFrmDst, (outs dstidx8:$dst), (ins), + "stosb\t{%al, $dst|$dst, al}", [], IIC_STOS>; let Defs = [EDI], Uses = [AX,EDI,EFLAGS] in -def STOSW : I<0xAB, RawFrm, (outs), (ins), "stosw", [], IIC_STOS>, OpSize; +def STOSW : I<0xAB, RawFrmDst, (outs dstidx16:$dst), (ins), + "stosw\t{%ax, $dst|$dst, ax}", [], IIC_STOS>, OpSize; let Defs = [EDI], Uses = [EAX,EDI,EFLAGS] in -def STOSL : I<0xAB, RawFrm, (outs), (ins), "stos{l|d}", [], IIC_STOS>, OpSize16; +def STOSL : I<0xAB, RawFrmDst, (outs dstidx32:$dst), (ins), + "stos{l|d}\t{%eax, $dst|$dst, eax}", [], IIC_STOS>, OpSize16; let Defs = [RCX,RDI], Uses = [RAX,RCX,RDI,EFLAGS] in -def STOSQ : RI<0xAB, RawFrm, (outs), (ins), "stosq", [], IIC_STOS>; +def STOSQ : RI<0xAB, RawFrmDst, (outs dstidx64:$dst), (ins), + "stosq\t{%rax, $dst|$dst, rax}", [], IIC_STOS>; def SCAS8 : I<0xAE, RawFrm, (outs), (ins), "scasb", [], IIC_SCAS>; def SCAS16 : I<0xAF, RawFrm, (outs), (ins), "scasw", [], IIC_SCAS>, OpSize; @@ -2380,6 +2420,18 @@ 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]>; +// stos aliases. Accept the source being omitted because it's implicit in +// the mnemonic, or the mnemonic suffix being omitted because it's implicit +// in the source. +def : InstAlias<"stosb $dst", (STOSB dstidx8:$dst), 0>; +def : InstAlias<"stosw $dst", (STOSW dstidx16:$dst), 0>; +def : InstAlias<"stos{l|d} $dst", (STOSL dstidx32:$dst), 0>; +def : InstAlias<"stosq $dst", (STOSQ dstidx64:$dst), 0>, Requires<[In64BitMode]>; +def : InstAlias<"stos {%al, $dst|$dst, al}", (STOSB dstidx8:$dst), 0>; +def : InstAlias<"stos {%ax, $dst|$dst, ax}", (STOSW dstidx16:$dst), 0>; +def : InstAlias<"stos {%eax, $dst|$dst, eax}", (STOSL dstidx32:$dst), 0>; +def : InstAlias<"stos {%rax, $dst|$dst, rax}", (STOSQ dstidx64:$dst), 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 index a5dd88b1d48..ffad9596c83 100644 --- a/test/MC/X86/index-operations.s +++ b/test/MC/X86/index-operations.s @@ -44,3 +44,33 @@ 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] + +stosw +// 64: stosw %ax, %es:(%rdi) # encoding: [0x66,0xab] +// 32: stosw %ax, %es:(%edi) # encoding: [0x66,0xab] +// 16: stosw %ax, %es:(%di) # encoding: [0xab] + +stos %eax, (%edi) +// 64: stosl %eax, %es:(%edi) # encoding: [0x67,0xab] +// 32: stosl %eax, %es:(%edi) # encoding: [0xab] +// 16: stosl %eax, %es:(%edi) # encoding: [0x66,0x67,0xab] + +stosb %al, %fs:(%edi) +// ERR64: invalid operand for instruction +// ERR32: invalid operand for instruction +// ERR16: invalid operand for instruction + +stosb %al, %es:(%edi) +// 64: stosb %al, %es:(%edi) # encoding: [0x67,0xaa] +// 32: stosb %al, %es:(%edi) # encoding: [0xaa] +// 16: stosb %al, %es:(%edi) # encoding: [0x67,0xaa] + +stosq +// 64: stosq %rax, %es:(%rdi) # encoding: [0x48,0xab] +// ERR32: 64-bit +// ERR16: 64-bit + +stos %rax, (%edi) +// 64: stosq %rax, %es:(%edi) # encoding: [0x48,0x67,0xab] +// ERR32: only available in 64-bit mode +// ERR16: only available in 64-bit mode diff --git a/test/MC/X86/x86-16.s b/test/MC/X86/x86-16.s index 4b54a027a88..41b5f51dbc7 100644 --- a/test/MC/X86/x86-16.s +++ b/test/MC/X86/x86-16.s @@ -878,21 +878,21 @@ pshufw $90, %mm4, %mm0 lods %ds:(%si), %eax lods (%si), %eax -// CHECK: stosb # encoding: [0xaa] +// CHECK: stosb %al, %es:(%di) # encoding: [0xaa] // CHECK: stosb // CHECK: stosb stosb stosb %al, %es:(%di) stos %al, %es:(%di) -// CHECK: stosw # encoding: [0xab] +// CHECK: stosw %ax, %es:(%di) # encoding: [0xab] // CHECK: stosw // CHECK: stosw stosw stosw %ax, %es:(%di) stos %ax, %es:(%di) -// CHECK: stosl # encoding: [0x66,0xab] +// CHECK: stosl %eax, %es:(%di) # encoding: [0x66,0xab] // CHECK: stosl // CHECK: stosl stosl diff --git a/test/MC/X86/x86-32.s b/test/MC/X86/x86-32.s index 29be52e35c4..e661f664b7e 100644 --- a/test/MC/X86/x86-32.s +++ b/test/MC/X86/x86-32.s @@ -954,21 +954,21 @@ pshufw $90, %mm4, %mm0 lods %ds:(%esi), %eax lods (%esi), %eax -// CHECK: stosb # encoding: [0xaa] +// CHECK: stosb %al, %es:(%edi) # encoding: [0xaa] // CHECK: stosb // CHECK: stosb stosb stosb %al, %es:(%edi) stos %al, %es:(%edi) -// CHECK: stosw # encoding: [0x66,0xab] +// CHECK: stosw %ax, %es:(%edi) # encoding: [0x66,0xab] // CHECK: stosw // CHECK: stosw stosw stosw %ax, %es:(%edi) stos %ax, %es:(%edi) -// CHECK: stosl # encoding: [0xab] +// CHECK: stosl %eax, %es:(%edi) # encoding: [0xab] // CHECK: stosl // CHECK: stosl stosl diff --git a/test/MC/X86/x86-64.s b/test/MC/X86/x86-64.s index ef798d7f080..08adfccf762 100644 --- a/test/MC/X86/x86-64.s +++ b/test/MC/X86/x86-64.s @@ -1160,28 +1160,28 @@ xsetbv // CHECK: xsetbv # encoding: [0x0f,0x01,0xd1] lods %ds:(%rsi), %rax lods (%rsi), %rax -// CHECK: stosb # encoding: [0xaa] +// CHECK: stosb %al, %es:(%rdi) # encoding: [0xaa] // CHECK: stosb // CHECK: stosb stosb stosb %al, %es:(%rdi) stos %al, %es:(%rdi) -// CHECK: stosw # encoding: [0x66,0xab] +// CHECK: stosw %ax, %es:(%rdi) # encoding: [0x66,0xab] // CHECK: stosw // CHECK: stosw stosw stosw %ax, %es:(%rdi) stos %ax, %es:(%rdi) -// CHECK: stosl # encoding: [0xab] +// CHECK: stosl %eax, %es:(%rdi) # encoding: [0xab] // CHECK: stosl // CHECK: stosl stosl stosl %eax, %es:(%rdi) stos %eax, %es:(%rdi) -// CHECK: stosq # encoding: [0x48,0xab] +// CHECK: stosq %rax, %es:(%rdi) # encoding: [0x48,0xab] // CHECK: stosq // CHECK: stosq stosq diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 1530c42f76a..12950518444 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -61,6 +61,7 @@ namespace X86Local { MRMSrcMem = 6, RawFrmMemOffs = 7, RawFrmSrc = 8, + RawFrmDst = 9, MRM0r = 16, MRM1r = 17, MRM2r = 18, MRM3r = 19, MRM4r = 20, MRM5r = 21, MRM6r = 22, MRM7r = 23, MRM0m = 24, MRM1m = 25, MRM2m = 26, MRM3m = 27, @@ -634,6 +635,9 @@ void RecognizableInstr::emitInstructionSpecifier() { case X86Local::RawFrmSrc: HANDLE_OPERAND(relocation); return; + case X86Local::RawFrmDst: + HANDLE_OPERAND(relocation); + return; case X86Local::RawFrm: // Operand 1 (optional) is an address or immediate. // Operand 2 (optional) is an immediate. @@ -1270,6 +1274,10 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("srcidx16", TYPE_SRCIDX16) TYPE("srcidx32", TYPE_SRCIDX32) TYPE("srcidx64", TYPE_SRCIDX64) + TYPE("dstidx8", TYPE_DSTIDX8) + TYPE("dstidx16", TYPE_DSTIDX16) + TYPE("dstidx32", TYPE_DSTIDX32) + TYPE("dstidx64", TYPE_DSTIDX64) TYPE("offset8", TYPE_MOFFS8) TYPE("offset16", TYPE_MOFFS16) TYPE("offset32", TYPE_MOFFS32) @@ -1486,6 +1494,10 @@ OperandEncoding RecognizableInstr::relocationEncodingFromString ENCODING("srcidx16", ENCODING_SI) ENCODING("srcidx32", ENCODING_SI) ENCODING("srcidx64", ENCODING_SI) + ENCODING("dstidx8", ENCODING_DI) + ENCODING("dstidx16", ENCODING_DI) + ENCODING("dstidx32", ENCODING_DI) + ENCODING("dstidx64", ENCODING_DI) errs() << "Unhandled relocation encoding " << s << "\n"; llvm_unreachable("Unhandled relocation encoding"); }