[llvm] r258132 - [X86] Adding support for missing variations of X86 string related instructions
Yatsina, Marina via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 20 06:13:01 PST 2016
Committed a fix in revision 258312.
Please let me know if you encounter additional issues.
From: Yatsina, Marina
Sent: Wednesday, January 20, 2016 14:19
To: 'Diego Novillo'
Cc: llvm-commits at lists.llvm.org
Subject: RE: [llvm] r258132 - [X86] Adding support for missing variations of X86 string related instructions
There is indeed a bug in my code because there’s an overloading of the “movsd” and “cmpsd” instructions, e.g. movsd can be either “Move Data from String to String” (the case I wanted to handle) or “Move or Merge Scalar Double-Precision Floating-Point Value” (the case that causes the unreachable).
Will have a fix soon.
BTW, you were right to change the asserts to llvm_unreachanbles.
Thanks,
Marina
From: Diego Novillo [mailto:dnovillo at google.com]
Sent: Wednesday, January 20, 2016 03:56
To: Yatsina, Marina
Cc: llvm-commits at lists.llvm.org<mailto:llvm-commits at lists.llvm.org>
Subject: Re: [llvm] r258132 - [X86] Adding support for missing variations of X86 string related instructions
There seems to be something buggy with this patch. In our internal builds, we enable -Wstring-conversion. This picked up a couple of bad invocations of assert() in the patch:
lib/Target/X86/AsmParser/X86AsmParser.cpp:1010:12: error: implicit conversion turns string literal into bool: 'const char [39]' to 'bool' [-Werror,-Wstring-conversion]
lib/Target/X86/AsmParser/X86AsmParser.cpp:1027:12: error: implicit conversion turns string literal into bool: 'const char [26]' to 'bool' [-Werror,-Wstring-conversion]
I fixed them by turning the assertions into llvm_unreachable() calls:
- assert("Only (R|E)SI and (R|E)DI are expected!");
+ llvm_unreachable("Only (R|E)SI and (R|E)DI are expected!");
- assert("Unexpected register class");
+ llvm_unreachable("Unexpected register class");
It turns out, that we are hitting these assertions in a couple of tests which are now failing with my patch. I believe this points to a problem with the original patch (r258132). These tests are now failing:
Failing Tests (2):
LLVM :: CodeGen/X86/pr3154.ll
LLVM :: MC/X86/x86-32-coverage.s
They are both hitting the llvm_unreachable("Unexpected register class") at lib/Target/X86/AsmParser/X86AsmParser.cpp:1027
Could you take a look or revert? Perhaps the intention was not to assert something else at that point?
Thanks. Diego.
On Tue, Jan 19, 2016 at 7:37 AM, Marina Yatsina via llvm-commits <llvm-commits at lists.llvm.org<mailto:llvm-commits at lists.llvm.org>> wrote:
Author: myatsina
Date: Tue Jan 19 09:37:56 2016
New Revision: 258132
URL: http://llvm.org/viewvc/llvm-project?rev=258132&view=rev
Log:
[X86] Adding support for missing variations of X86 string related instructions
The following are legal according to X86 spec:
ins mem, DX
outs DX, mem
lods mem
stos mem
scas mem
cmps mem, mem
movs mem, mem
Differential Revision: http://reviews.llvm.org/D14827
Modified:
llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp
llvm/trunk/lib/Target/X86/X86InstrInfo.td
llvm/trunk/test/MC/X86/index-operations.s
llvm/trunk/test/MC/X86/intel-syntax.s
Modified: llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp?rev=258132&r1=258131&r2=258132&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp (original)
+++ llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp Tue Jan 19 09:37:56 2016
@@ -683,9 +683,14 @@ private:
std::unique_ptr<X86Operand> DefaultMemSIOperand(SMLoc Loc);
std::unique_ptr<X86Operand> DefaultMemDIOperand(SMLoc Loc);
- void AddDefaultSrcDestOperands(
- OperandVector& Operands, std::unique_ptr<llvm::MCParsedAsmOperand> &&Src,
- std::unique_ptr<llvm::MCParsedAsmOperand> &&Dst);
+ bool IsSIReg(unsigned Reg);
+ unsigned GetSIDIForRegClass(unsigned RegClassID, unsigned Reg, bool IsSIReg);
+ void
+ AddDefaultSrcDestOperands(OperandVector &Operands,
+ std::unique_ptr<llvm::MCParsedAsmOperand> &&Src,
+ std::unique_ptr<llvm::MCParsedAsmOperand> &&Dst);
+ bool VerifyAndAdjustOperands(OperandVector &OrigOperands,
+ OperandVector &FinalOperands);
std::unique_ptr<X86Operand> ParseOperand();
std::unique_ptr<X86Operand> ParseATTOperand();
std::unique_ptr<X86Operand> ParseIntelOperand();
@@ -747,11 +752,6 @@ private:
bool OmitRegisterFromClobberLists(unsigned RegNo) override;
- /// doSrcDstMatch - Returns true if operands are matching in their
- /// word size (%si and %di, %esi and %edi, etc.). Order depends on
- /// the parsing mode (Intel vs. AT&T).
- bool doSrcDstMatch(X86Operand &Op1, X86Operand &Op2);
-
/// Parses AVX512 specific operand primitives: masked registers ({%k<NUM>}, {z})
/// and memory broadcasting ({1to<NUM>}) primitives, updating Operands vector if required.
/// \return \c true if no parsing errors occurred, \c false otherwise.
@@ -867,27 +867,6 @@ static bool CheckBaseRegAndIndexReg(unsi
return false;
}
-bool X86AsmParser::doSrcDstMatch(X86Operand &Op1, X86Operand &Op2)
-{
- // Return true and let a normal complaint about bogus operands happen.
- if (!Op1.isMem() || !Op2.isMem())
- return true;
-
- // Actually these might be the other way round if Intel syntax is
- // being used. It doesn't matter.
- unsigned diReg = Op1.Mem.BaseReg;
- unsigned siReg = Op2.Mem.BaseReg;
-
- if (X86MCRegisterClasses[X86::GR16RegClassID].contains(siReg))
- return X86MCRegisterClasses[X86::GR16RegClassID].contains(diReg);
- if (X86MCRegisterClasses[X86::GR32RegClassID].contains(siReg))
- return X86MCRegisterClasses[X86::GR32RegClassID].contains(diReg);
- if (X86MCRegisterClasses[X86::GR64RegClassID].contains(siReg))
- return X86MCRegisterClasses[X86::GR64RegClassID].contains(diReg);
- // Again, return true and let another error happen.
- return true;
-}
-
bool X86AsmParser::ParseRegister(unsigned &RegNo,
SMLoc &StartLoc, SMLoc &EndLoc) {
MCAsmParser &Parser = getParser();
@@ -1025,6 +1004,37 @@ std::unique_ptr<X86Operand> X86AsmParser
Loc, Loc, 0);
}
+bool X86AsmParser::IsSIReg(unsigned Reg) {
+ switch (Reg) {
+ default:
+ assert("Only (R|E)SI and (R|E)DI are expected!");
+ return false;
+ case X86::RSI:
+ case X86::ESI:
+ case X86::SI:
+ return true;
+ case X86::RDI:
+ case X86::EDI:
+ case X86::DI:
+ return false;
+ }
+}
+
+unsigned X86AsmParser::GetSIDIForRegClass(unsigned RegClassID, unsigned Reg,
+ bool IsSIReg) {
+ switch (RegClassID) {
+ default:
+ assert("Unexpected register class");
+ return Reg;
+ case X86::GR64RegClassID:
+ return IsSIReg ? X86::RSI : X86::RDI;
+ case X86::GR32RegClassID:
+ return IsSIReg ? X86::ESI : X86::EDI;
+ case X86::GR16RegClassID:
+ return IsSIReg ? X86::SI : X86::DI;
+ }
+}
+
void X86AsmParser::AddDefaultSrcDestOperands(
OperandVector& Operands, std::unique_ptr<llvm::MCParsedAsmOperand> &&Src,
std::unique_ptr<llvm::MCParsedAsmOperand> &&Dst) {
@@ -1038,6 +1048,76 @@ void X86AsmParser::AddDefaultSrcDestOper
}
}
+bool X86AsmParser::VerifyAndAdjustOperands(OperandVector &OrigOperands,
+ OperandVector &FinalOperands) {
+
+ if (OrigOperands.size() > 1) {
+ // Check if sizes match, OrigOpernads also contains the instruction name
+ assert(OrigOperands.size() == FinalOperands.size() + 1 &&
+ "Opernand size mismatch");
+
+ // Verify types match
+ int RegClassID = -1;
+ for (unsigned int i = 0; i < FinalOperands.size(); ++i) {
+ X86Operand &OrigOp = static_cast<X86Operand &>(*OrigOperands[i + 1]);
+ X86Operand &FinalOp = static_cast<X86Operand &>(*FinalOperands[i]);
+
+ if (FinalOp.isReg() &&
+ (!OrigOp.isReg() || FinalOp.getReg() != OrigOp.getReg()))
+ // Return false and let a normal complaint about bogus operands happen
+ return false;
+
+ if (FinalOp.isMem()) {
+
+ if (!OrigOp.isMem())
+ // Return false and let a normal complaint about bogus operands happen
+ return false;
+
+ unsigned OrigReg = OrigOp.Mem.BaseReg;
+ unsigned FinalReg = FinalOp.Mem.BaseReg;
+
+ // If we've already encounterd a register class, make sure all register
+ // bases are of the same register class
+ if (RegClassID != -1 &&
+ !X86MCRegisterClasses[RegClassID].contains(OrigReg)) {
+ return Error(OrigOp.getStartLoc(),
+ "mismatching source and destination index registers");
+ }
+
+ if (X86MCRegisterClasses[X86::GR64RegClassID].contains(OrigReg))
+ RegClassID = X86::GR64RegClassID;
+ else if (X86MCRegisterClasses[X86::GR32RegClassID].contains(OrigReg))
+ RegClassID = X86::GR32RegClassID;
+ else if (X86MCRegisterClasses[X86::GR16RegClassID].contains(OrigReg))
+ RegClassID = X86::GR16RegClassID;
+
+ bool IsSI = IsSIReg(FinalReg);
+ FinalReg = GetSIDIForRegClass(RegClassID, FinalReg, IsSI);
+
+ if (FinalReg != OrigReg) {
+ std::string RegName = IsSI ? "ES:(R|E)SI" : "ES:(R|E)DI";
+ Warning(OrigOp.getStartLoc(),
+ "memory operand is only for determining the size, " +
+ RegName + " will be used for the location");
+ }
+
+ FinalOp.Mem.Size = OrigOp.Mem.Size;
+ FinalOp.Mem.SegReg = OrigOp.Mem.SegReg;
+ FinalOp.Mem.BaseReg = FinalReg;
+ }
+ }
+
+ // Remove old operandss
+ for (unsigned int i = 0; i < FinalOperands.size(); ++i)
+ OrigOperands.pop_back();
+ }
+ // OrigOperands.append(FinalOperands.begin(), FinalOperands.end());
+ for (unsigned int i = 0; i < FinalOperands.size(); ++i)
+ OrigOperands.push_back(std::move(FinalOperands[i]));
+
+ return false;
+}
+
std::unique_ptr<X86Operand> X86AsmParser::ParseOperand() {
if (isParsingIntelSyntax())
return ParseIntelOperand();
@@ -2274,84 +2354,92 @@ bool X86AsmParser::ParseInstruction(Pars
}
}
+ SmallVector<std::unique_ptr<MCParsedAsmOperand>, 2> TmpOperands;
+ bool HadVerifyError = false;
+
// Append default arguments to "ins[bwld]"
- if (Name.startswith("ins") && Operands.size() == 1 &&
- (Name == "insb" || Name == "insw" || Name == "insl" || Name == "insd")) {
- AddDefaultSrcDestOperands(Operands,
+ if (Name.startswith("ins") &&
+ (Operands.size() == 1 || Operands.size() == 3) &&
+ (Name == "insb" || Name == "insw" || Name == "insl" || Name == "insd" ||
+ Name == "ins")) {
+
+ AddDefaultSrcDestOperands(TmpOperands,
X86Operand::CreateReg(X86::DX, NameLoc, NameLoc),
DefaultMemDIOperand(NameLoc));
+ HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
}
// Append default arguments to "outs[bwld]"
- if (Name.startswith("outs") && Operands.size() == 1 &&
+ if (Name.startswith("outs") &&
+ (Operands.size() == 1 || Operands.size() == 3) &&
(Name == "outsb" || Name == "outsw" || Name == "outsl" ||
- Name == "outsd" )) {
- AddDefaultSrcDestOperands(Operands,
- DefaultMemSIOperand(NameLoc),
+ Name == "outsd" || Name == "outs")) {
+ AddDefaultSrcDestOperands(TmpOperands, DefaultMemSIOperand(NameLoc),
X86Operand::CreateReg(X86::DX, NameLoc, NameLoc));
+ HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
}
// 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 &&
+ if (Name.startswith("lods") &&
+ (Operands.size() == 1 || Operands.size() == 2) &&
(Name == "lods" || Name == "lodsb" || Name == "lodsw" ||
- Name == "lodsl" || Name == "lodsd" || Name == "lodsq"))
- Operands.push_back(DefaultMemSIOperand(NameLoc));
+ Name == "lodsl" || Name == "lodsd" || Name == "lodsq")) {
+ TmpOperands.push_back(DefaultMemSIOperand(NameLoc));
+ HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
+ }
// 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 &&
+ if (Name.startswith("stos") &&
+ (Operands.size() == 1 || Operands.size() == 2) &&
(Name == "stos" || Name == "stosb" || Name == "stosw" ||
- Name == "stosl" || Name == "stosd" || Name == "stosq"))
- Operands.push_back(DefaultMemDIOperand(NameLoc));
+ Name == "stosl" || Name == "stosd" || Name == "stosq")) {
+ TmpOperands.push_back(DefaultMemDIOperand(NameLoc));
+ HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
+ }
// Transform "scas[bwlq]" into "scas[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("scas") && Operands.size() == 1 &&
+ if (Name.startswith("scas") &&
+ (Operands.size() == 1 || Operands.size() == 2) &&
(Name == "scas" || Name == "scasb" || Name == "scasw" ||
- Name == "scasl" || Name == "scasd" || Name == "scasq"))
- Operands.push_back(DefaultMemDIOperand(NameLoc));
+ Name == "scasl" || Name == "scasd" || Name == "scasq")) {
+ TmpOperands.push_back(DefaultMemDIOperand(NameLoc));
+ HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
+ }
// Add default SI and DI operands to "cmps[bwlq]".
if (Name.startswith("cmps") &&
+ (Operands.size() == 1 || Operands.size() == 3) &&
(Name == "cmps" || Name == "cmpsb" || Name == "cmpsw" ||
Name == "cmpsl" || Name == "cmpsd" || Name == "cmpsq")) {
- if (Operands.size() == 1) {
- AddDefaultSrcDestOperands(Operands,
- DefaultMemDIOperand(NameLoc),
- DefaultMemSIOperand(NameLoc));
- } else if (Operands.size() == 3) {
- X86Operand &Op = (X86Operand &)*Operands[1];
- X86Operand &Op2 = (X86Operand &)*Operands[2];
- if (!doSrcDstMatch(Op, Op2))
- return Error(Op.getStartLoc(),
- "mismatching source and destination index registers");
- }
+ AddDefaultSrcDestOperands(TmpOperands, DefaultMemDIOperand(NameLoc),
+ DefaultMemSIOperand(NameLoc));
+ HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
}
// Add default SI and DI operands to "movs[bwlq]".
- if ((Name.startswith("movs") &&
- (Name == "movs" || Name == "movsb" || Name == "movsw" ||
- Name == "movsl" || Name == "movsd" || Name == "movsq")) ||
- (Name.startswith("smov") &&
- (Name == "smov" || Name == "smovb" || Name == "smovw" ||
- Name == "smovl" || Name == "smovd" || Name == "smovq"))) {
- if (Operands.size() == 1) {
- if (Name == "movsd")
- Operands.back() = X86Operand::CreateToken("movsl", NameLoc);
- AddDefaultSrcDestOperands(Operands,
- DefaultMemSIOperand(NameLoc),
- DefaultMemDIOperand(NameLoc));
- } else if (Operands.size() == 3) {
- X86Operand &Op = (X86Operand &)*Operands[1];
- X86Operand &Op2 = (X86Operand &)*Operands[2];
- if (!doSrcDstMatch(Op, Op2))
- return Error(Op.getStartLoc(),
- "mismatching source and destination index registers");
- }
+ if (((Name.startswith("movs") &&
+ (Name == "movs" || Name == "movsb" || Name == "movsw" ||
+ Name == "movsl" || Name == "movsd" || Name == "movsq")) ||
+ (Name.startswith("smov") &&
+ (Name == "smov" || Name == "smovb" || Name == "smovw" ||
+ Name == "smovl" || Name == "smovd" || Name == "smovq"))) &&
+ (Operands.size() == 1 || Operands.size() == 3)) {
+ if (Name == "movsd" && Operands.size() == 1)
+ Operands.back() = X86Operand::CreateToken("movsl", NameLoc);
+ AddDefaultSrcDestOperands(TmpOperands, DefaultMemSIOperand(NameLoc),
+ DefaultMemDIOperand(NameLoc));
+ HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
+ }
+
+ // Check if we encountered an error for one the string insturctions
+ if (HadVerifyError) {
+ return HadVerifyError;
}
// FIXME: Hack to handle recognize s{hr,ar,hl} $1, <op>. Canonicalize to
Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.td?rev=258132&r1=258131&r2=258132&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86InstrInfo.td (original)
+++ llvm/trunk/lib/Target/X86/X86InstrInfo.td Tue Jan 19 09:37:56 2016
@@ -2782,6 +2782,11 @@ def : InstAlias<"lods\t{$src, %al|al, $s
def : InstAlias<"lods\t{$src, %ax|ax, $src}", (LODSW srcidx16:$src), 0>;
def : InstAlias<"lods\t{$src, %eax|eax, $src}", (LODSL srcidx32:$src), 0>;
def : InstAlias<"lods\t{$src, %rax|rax, $src}", (LODSQ srcidx64:$src), 0>, Requires<[In64BitMode]>;
+def : InstAlias<"lods\t$src", (LODSB srcidx8:$src), 0>;
+def : InstAlias<"lods\t$src", (LODSW srcidx16:$src), 0>;
+def : InstAlias<"lods\t$src", (LODSL srcidx32:$src), 0>;
+def : InstAlias<"lods\t$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
@@ -2794,6 +2799,11 @@ def : InstAlias<"stos\t{%al, $dst|$dst,
def : InstAlias<"stos\t{%ax, $dst|$dst, ax}", (STOSW dstidx16:$dst), 0>;
def : InstAlias<"stos\t{%eax, $dst|$dst, eax}", (STOSL dstidx32:$dst), 0>;
def : InstAlias<"stos\t{%rax, $dst|$dst, rax}", (STOSQ dstidx64:$dst), 0>, Requires<[In64BitMode]>;
+def : InstAlias<"stos\t$dst", (STOSB dstidx8:$dst), 0>;
+def : InstAlias<"stos\t$dst", (STOSW dstidx16:$dst), 0>;
+def : InstAlias<"stos\t$dst", (STOSL dstidx32:$dst), 0>;
+def : InstAlias<"stos\t$dst", (STOSQ dstidx64:$dst), 0>, Requires<[In64BitMode]>;
+
// scas aliases. Accept the destination being omitted because it's implicit
// in the mnemonic, or the mnemonic suffix being omitted because it's implicit
@@ -2806,6 +2816,24 @@ def : InstAlias<"scas\t{$dst, %al|al, $d
def : InstAlias<"scas\t{$dst, %ax|ax, $dst}", (SCASW dstidx16:$dst), 0>;
def : InstAlias<"scas\t{$dst, %eax|eax, $dst}", (SCASL dstidx32:$dst), 0>;
def : InstAlias<"scas\t{$dst, %rax|rax, $dst}", (SCASQ dstidx64:$dst), 0>, Requires<[In64BitMode]>;
+def : InstAlias<"scas\t$dst", (SCASB dstidx8:$dst), 0>;
+def : InstAlias<"scas\t$dst", (SCASW dstidx16:$dst), 0>;
+def : InstAlias<"scas\t$dst", (SCASL dstidx32:$dst), 0>;
+def : InstAlias<"scas\t$dst", (SCASQ dstidx64:$dst), 0>, Requires<[In64BitMode]>;
+
+// cmps aliases. Mnemonic suffix being omitted because it's implicit
+// in the destination.
+def : InstAlias<"cmps\t{$dst, $src|$src, $dst}", (CMPSB dstidx8:$dst, srcidx8:$src), 0>;
+def : InstAlias<"cmps\t{$dst, $src|$src, $dst}", (CMPSW dstidx16:$dst, srcidx16:$src), 0>;
+def : InstAlias<"cmps\t{$dst, $src|$src, $dst}", (CMPSL dstidx32:$dst, srcidx32:$src), 0>;
+def : InstAlias<"cmps\t{$dst, $src|$src, $dst}", (CMPSQ dstidx64:$dst, srcidx64:$src), 0>, Requires<[In64BitMode]>;
+
+// movs aliases. Mnemonic suffix being omitted because it's implicit
+// in the destination.
+def : InstAlias<"movs\t{$src, $dst|$dst, $src}", (MOVSB dstidx8:$dst, srcidx8:$src), 0>;
+def : InstAlias<"movs\t{$src, $dst|$dst, $src}", (MOVSW dstidx16:$dst, srcidx16:$src), 0>;
+def : InstAlias<"movs\t{$src, $dst|$dst, $src}", (MOVSL dstidx32:$dst, srcidx32:$src), 0>;
+def : InstAlias<"movs\t{$src, $dst|$dst, $src}", (MOVSQ dstidx64:$dst, 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)>;
@@ -2918,6 +2946,18 @@ def : InstAlias<"imul{l}\t{$imm, $r|$r,
def : InstAlias<"imul{q}\t{$imm, $r|$r, $imm}", (IMUL64rri32 GR64:$r, GR64:$r, i64i32imm:$imm), 0>;
def : InstAlias<"imul{q}\t{$imm, $r|$r, $imm}", (IMUL64rri8 GR64:$r, GR64:$r, i64i8imm:$imm), 0>;
+// ins aliases. Accept the mnemonic suffix being omitted because it's implicit
+// in the destination.
+def : InstAlias<"ins\t{%dx, $dst|$dst, dx}", (INSB dstidx8:$dst), 0>;
+def : InstAlias<"ins\t{%dx, $dst|$dst, dx}", (INSW dstidx16:$dst), 0>;
+def : InstAlias<"ins\t{%dx, $dst|$dst, dx}", (INSL dstidx32:$dst), 0>;
+
+// outs aliases. Accept the mnemonic suffix being omitted because it's implicit
+// in the source.
+def : InstAlias<"outs\t{$src, %dx|dx, $src}", (OUTSB srcidx8:$src), 0>;
+def : InstAlias<"outs\t{$src, %dx|dx, $src}", (OUTSW srcidx16:$src), 0>;
+def : InstAlias<"outs\t{$src, %dx|dx, $src}", (OUTSL srcidx32:$src), 0>;
+
// inb %dx -> inb %al, %dx
def : InstAlias<"inb\t{%dx|dx}", (IN8rr), 0>;
def : InstAlias<"inw\t{%dx|dx}", (IN16rr), 0>;
Modified: llvm/trunk/test/MC/X86/index-operations.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/X86/index-operations.s?rev=258132&r1=258131&r2=258132&view=diff
==============================================================================
--- llvm/trunk/test/MC/X86/index-operations.s (original)
+++ llvm/trunk/test/MC/X86/index-operations.s Tue Jan 19 09:37:56 2016
@@ -144,3 +144,19 @@ insw %dx, (%edi)
// 64: insw %dx, %es:(%edi) # encoding: [0x66,0x67,0x6d]
// 32: insw %dx, %es:(%edi) # encoding: [0x66,0x6d]
// 16: insw %dx, %es:(%edi) # encoding: [0x67,0x6d]
+
+insw %dx, (%bx)
+// ERR64: invalid 16-bit base register
+// 32: insw %dx, %es:(%di) # encoding: [0x66,0x67,0x6d]
+// 16: insw %dx, %es:(%di) # encoding: [0x6d]
+
+insw %dx, (%ebx)
+// 64: insw %dx, %es:(%edi) # encoding: [0x66,0x67,0x6d]
+// 32: insw %dx, %es:(%edi) # encoding: [0x66,0x6d]
+// 16: insw %dx, %es:(%edi) # encoding: [0x67,0x6d]
+
+insw %dx, (%rbx)
+// 64: insw %dx, %es:(%rdi) # encoding: [0x66,0x6d]
+// ERR32: 64-bit
+// ERR16: 64-bit
+
Modified: llvm/trunk/test/MC/X86/intel-syntax.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/X86/intel-syntax.s?rev=258132&r1=258131&r2=258132&view=diff
==============================================================================
--- llvm/trunk/test/MC/X86/intel-syntax.s (original)
+++ llvm/trunk/test/MC/X86/intel-syntax.s Tue Jan 19 09:37:56 2016
@@ -751,3 +751,27 @@ loopnz _foo
sidt fword ptr [eax]
// CHECK: sidtq (%eax)
+
+ins byte ptr [eax], dx
+// CHECK: insb %dx, %es:(%edi)
+// CHECK-STDERR: memory operand is only for determining the size, ES:(R|E)DI will be used for the location
+outs dx, word ptr [eax]
+// CHECK: outsw (%esi), %dx
+// CHECK-STDERR: memory operand is only for determining the size, ES:(R|E)SI will be used for the location
+lods dword ptr [eax]
+// CHECK: lodsl (%esi), %eax
+// CHECK-STDERR: memory operand is only for determining the size, ES:(R|E)SI will be used for the location
+stos qword ptr [eax]
+// CHECK: stosq %rax, %es:(%edi)
+// CHECK-STDERR: memory operand is only for determining the size, ES:(R|E)DI will be used for the location
+scas byte ptr [eax]
+// CHECK: scasb %es:(%edi), %al
+// CHECK-STDERR: memory operand is only for determining the size, ES:(R|E)DI will be used for the location
+cmps word ptr [eax], word ptr [ebx]
+// CHECK: cmpsw %es:(%edi), (%esi)
+// CHECK-STDERR: memory operand is only for determining the size, ES:(R|E)SI will be used for the location
+// CHECK-STDERR: memory operand is only for determining the size, ES:(R|E)DI will be used for the location
+movs dword ptr [eax], dword ptr [ebx]
+// CHECK: movsl (%esi), %es:(%edi)
+// CHECK-STDERR: memory operand is only for determining the size, ES:(R|E)DI will be used for the location
+// CHECK-STDERR: memory operand is only for determining the size, ES:(R|E)SI will be used for the location
_______________________________________________
llvm-commits mailing list
llvm-commits at lists.llvm.org<mailto:llvm-commits at lists.llvm.org>
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
---------------------------------------------------------------------
Intel Israel (74) Limited
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160120/38cbc145/attachment-0001.html>
More information about the llvm-commits
mailing list