diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 03a9a332ce9..01f09eeac0c 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -1154,11 +1154,15 @@ def XCHG64rr : RI<0x87, MRMSrcReg, (outs GR64:$dst), (ins GR64:$val,GR64:$src), "xchg{q}\t{$val, $src|$src, $val}", []>; } -def XCHG16ar : I<0x90, AddRegFrm, (outs), (ins GR16_NOAX:$src), +def XCHG16ar : I<0x90, AddRegFrm, (outs), (ins GR16:$src), "xchg{w}\t{$src, %ax|AX, $src}", []>, OpSize; -def XCHG32ar : I<0x90, AddRegFrm, (outs), (ins GR32_NOAX:$src), - "xchg{l}\t{$src, %eax|EAX, $src}", []>; -def XCHG64ar : RI<0x90, AddRegFrm, (outs), (ins GR64_NOAX:$src), +def XCHG32ar : I<0x90, AddRegFrm, (outs), (ins GR32:$src), + "xchg{l}\t{$src, %eax|EAX, $src}", []>, Requires<[In32BitMode]>; +// Uses GR32_NOAX in 64-bit mode to prevent encoding using the 0x90 NOP encoding. +// xchg %eax, %eax needs to clear upper 32-bits of RAX so is not a NOP. +def XCHG32ar64 : I<0x90, AddRegFrm, (outs), (ins GR32_NOAX:$src), + "xchg{l}\t{$src, %eax|EAX, $src}", []>, Requires<[In64BitMode]>; +def XCHG64ar : RI<0x90, AddRegFrm, (outs), (ins GR64:$src), "xchg{q}\t{$src, %rax|RAX, $src}", []>; @@ -1716,6 +1720,7 @@ def : InstAlias<"xchgl $mem, $val", (XCHG32rm GR32:$val, i32mem:$mem)>; def : InstAlias<"xchgq $mem, $val", (XCHG64rm GR64:$val, i64mem:$mem)>; // xchg: We accept "xchgX , %eax" and "xchgX %eax, " as synonyms. -def : InstAlias<"xchgw %ax, $src", (XCHG16ar GR16_NOAX:$src)>; -def : InstAlias<"xchgl %eax, $src", (XCHG32ar GR32_NOAX:$src)>; -def : InstAlias<"xchgq %rax, $src", (XCHG64ar GR64_NOAX:$src)>; +def : InstAlias<"xchgw %ax, $src", (XCHG16ar GR16:$src)>; +def : InstAlias<"xchgl %eax, $src", (XCHG32ar GR32:$src)>, Requires<[In32BitMode]>; +def : InstAlias<"xchgl %eax, $src", (XCHG32ar64 GR32_NOAX:$src)>, Requires<[In64BitMode]>; +def : InstAlias<"xchgq %rax, $src", (XCHG64ar GR64:$src)>; diff --git a/lib/Target/X86/X86RegisterInfo.td b/lib/Target/X86/X86RegisterInfo.td index 3f81d3b65ac..9a7db36e087 100644 --- a/lib/Target/X86/X86RegisterInfo.td +++ b/lib/Target/X86/X86RegisterInfo.td @@ -390,21 +390,11 @@ def GR64_NOREX : RegisterClass<"X86", [i64], 64, (GR32_NOREX sub_32bit)]; } -// GR16_NOAX - GR16 registers except AX. -def GR16_NOAX : RegisterClass<"X86", [i16], 16, (sub GR16, AX)> { - let SubRegClasses = [(GR8 sub_8bit, sub_8bit_hi)]; -} - -// GR32_NOAX - GR32 registers except EAX. +// GR32_NOAX - GR32 registers except EAX. Used by AddRegFrm of XCHG32 in 64-bit +// mode to prevent encoding using the 0x90 NOP encoding. xchg %eax, %eax needs +// to clear upper 32-bits of RAX so is not a NOP. def GR32_NOAX : RegisterClass<"X86", [i32], 32, (sub GR32, EAX)> { - let SubRegClasses = [(GR8 sub_8bit, sub_8bit_hi), (GR16_NOAX sub_16bit)]; -} - -// GR64_NOAX - GR64 registers except RAX. -def GR64_NOAX : RegisterClass<"X86", [i64], 64, (sub GR64, RAX)> { - let SubRegClasses = [(GR8 sub_8bit, sub_8bit_hi), - (GR16_NOAX sub_16bit), - (GR32_NOAX sub_32bit)]; + let SubRegClasses = [(GR8 sub_8bit, sub_8bit_hi), (GR16 sub_16bit)]; } // GR32_NOSP - GR32 registers except ESP. diff --git a/test/MC/X86/x86-32.s b/test/MC/X86/x86-32.s index 41226474a79..19f14450fee 100644 --- a/test/MC/X86/x86-32.s +++ b/test/MC/X86/x86-32.s @@ -948,11 +948,11 @@ fsubp %st, %st(2) // PR10345 // CHECK: xchgl %eax, %eax -// CHECK: encoding: [0x87,0xc0] +// CHECK: encoding: [0x90] xchgl %eax, %eax // CHECK: xchgw %ax, %ax -// CHECK: encoding: [0x66,0x87,0xc0] +// CHECK: encoding: [0x66,0x90] xchgw %ax, %ax // CHECK: xchgl %ecx, %eax diff --git a/test/MC/X86/x86-64.s b/test/MC/X86/x86-64.s index 23fa54f0d6b..a9cdaa495f0 100644 --- a/test/MC/X86/x86-64.s +++ b/test/MC/X86/x86-64.s @@ -1173,7 +1173,7 @@ pclmulqdq $0, (%rdi), %xmm1 // PR10345 // CHECK: xchgq %rax, %rax -// CHECK: encoding: [0x48,0x87,0xc0] +// CHECK: encoding: [0x48,0x90] xchgq %rax, %rax // CHECK: xchgl %eax, %eax @@ -1181,7 +1181,7 @@ xchgq %rax, %rax xchgl %eax, %eax // CHECK: xchgw %ax, %ax -// CHECK: encoding: [0x66,0x87,0xc0] +// CHECK: encoding: [0x66,0x90] xchgw %ax, %ax // CHECK: xchgl %ecx, %eax diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index 218a1a227c5..f42119c0740 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -620,6 +620,7 @@ void DisassemblerTables::setTableFields(ModRMDecision &decision, if(previousInfo.name == "NOOP" && (newInfo.name == "XCHG16ar" || newInfo.name == "XCHG32ar" || + newInfo.name == "XCHG32ar64" || newInfo.name == "XCHG64ar")) continue; // special case for XCHG*ar and NOOP