forked from OSchip/llvm-project
[x86] Allow segment and address-size overrides for LODS[BWLQ] (PR9385)
llvm-svn: 199803
This commit is contained in:
parent
db1ad12ae2
commit
2ef8d9c05c
|
@ -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<MCConstantExpr>(getMemDisp()) &&
|
||||
cast<MCConstantExpr>(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<X86Operand*>(Operands[1]);
|
||||
X86Operand *Op2 = static_cast<X86Operand*>(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<X86Operand*>(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" ||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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") \
|
||||
|
|
|
@ -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("<mem:");
|
||||
|
||||
// If this has a segment register, print it.
|
||||
if (SegReg.getReg()) {
|
||||
printOperand(MI, Op+1, O);
|
||||
O << ':';
|
||||
}
|
||||
|
||||
O << "(";
|
||||
printOperand(MI, Op, O);
|
||||
O << ")";
|
||||
|
||||
O << markup(">");
|
||||
}
|
||||
|
||||
void X86ATTInstPrinter::printMemOffset(const MCInst *MI, unsigned Op,
|
||||
raw_ostream &O) {
|
||||
const MCOperand &DispSpec = MI->getOperand(Op);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -445,6 +445,26 @@ def brtarget8 : Operand<OtherVT>;
|
|||
|
||||
}
|
||||
|
||||
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<iPTR> {
|
||||
let ParserMatchClass = X86SrcIdx8Operand;
|
||||
let MIOperandInfo = (ops ptr_rc, i8imm);
|
||||
let PrintMethod = "printSrcIdx8"; }
|
||||
def srcidx16 : Operand<iPTR> {
|
||||
let ParserMatchClass = X86SrcIdx16Operand;
|
||||
let MIOperandInfo = (ops ptr_rc, i8imm);
|
||||
let PrintMethod = "printSrcIdx16"; }
|
||||
def srcidx32 : Operand<iPTR> {
|
||||
let ParserMatchClass = X86SrcIdx32Operand;
|
||||
let MIOperandInfo = (ops ptr_rc, i8imm);
|
||||
let PrintMethod = "printSrcIdx32"; }
|
||||
def srcidx64 : Operand<iPTR> {
|
||||
let ParserMatchClass = X86SrcIdx64Operand;
|
||||
let MIOperandInfo = (ops ptr_rc, i8imm);
|
||||
let PrintMethod = "printSrcIdx64"; }
|
||||
def offset8 : Operand<iPTR> {
|
||||
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)>;
|
||||
|
|
|
@ -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]
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue