Skip to content

Commit

Permalink
[x86] Allow segment and address-size overrides for LODS[BWLQ] (PR9385)
Browse files Browse the repository at this point in the history
llvm-svn: 199803
  • Loading branch information
dwmw2 committed Jan 22, 2014
1 parent db1ad12 commit 2ef8d9c
Show file tree
Hide file tree
Showing 17 changed files with 280 additions and 45 deletions.
70 changes: 41 additions & 29 deletions llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ class X86AsmParser : public MCTargetAsmParser {
return 0;
}

X86Operand *DefaultMemSIOperand(SMLoc Loc);
X86Operand *ParseOperand();
X86Operand *ParseATTOperand();
X86Operand *ParseIntelOperand();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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" ||
Expand Down
25 changes: 25 additions & 0 deletions llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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") \
Expand Down
19 changes: 19 additions & 0 deletions llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class X86ATTInstPrinter : public MCInstPrinter {
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);

Expand Down Expand Up @@ -89,6 +90,18 @@ class X86ATTInstPrinter : public MCInstPrinter {
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);
}
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/Target/X86/InstPrinter/X86IntelInstPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class X86IntelInstPrinter : public MCInstPrinter {
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) {
Expand Down Expand Up @@ -100,6 +101,23 @@ class X86IntelInstPrinter : public MCInstPrinter {
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);
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, ...
Expand Down Expand Up @@ -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;
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/X86/X86InstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
Loading

0 comments on commit 2ef8d9c

Please sign in to comment.