This adds MOVQ variants as mandated by the Intel EM64T manuals. AMD's manuals use the MOVD mnemonic for both 32- and 64-bit moves between MMX/XMM registers and general registers (or memory), not recognizing that the 'D' suffix stands for the operand size. It also eliminates needless emission (in Intel mode) of REX64 prefixes on those MOVQ-s that only allow for MMX or XMM registers. What I'd really like to do here in a subsequent step (and if nobody objects beforehand) is to leave (for compatibility reasons) only the MOVD patterns, but convert the MOVQ ones to MOV ones allowing for a 'Q' suffix (and the 'L' suffix for those that deal with general registers). This would result in one minor oddity: a suffixless MOV between XMM registers or from/to XMM registers and memory could, by the unsuspicious, be expected to move the full 128 bits, but in fact (since there is no such MOV instruction), being a shortcut for MOVQ. But perhaps it wouldn't be very difficult to enforce the use of a suffix for this special case to avoid the potential confusion... Built and tested on x86_64-unknown-linux-gnu. Jan include/opcode/ 2005-07-06 Jan Beulich * i386.h (i386_optab): Add comment to movd. Use LongMem for all movd-s. Add NoRex64 to movq-s dealing only with mmx or xmm registers. Add movq-s as 64-bit variants of movd-s. --- /home/jbeulich/src/binutils/mainline/2005-07-05/include/opcode/i386.h 2005-07-05 09:14:29.000000000 +0200 +++ 2005-07-05/include/opcode/i386.h 2005-07-06 13:47:21.225834856 +0200 @@ -995,16 +995,24 @@ static const template i386_optab[] = /* MMX/SSE2 instructions. */ {"emms", 0, 0x0f77, X, CpuMMX, NoSuf, { 0, 0, 0 } }, +/* These really shouldn't allow for Reg64 (movq is the right mnemonic for + copying between Reg64/Mem64 and RegXMM/RegMMX, as is mandated by Intel's + spec). AMD's spec, having been in existence for much longer, failed to + recognize that and specified movd for 32- and 64-bit operations. */ {"movd", 2, 0x0f6e, X, CpuMMX, NoSuf|IgnoreSize|Modrm, { Reg32|Reg64|LongMem, RegMMX, 0 } }, {"movd", 2, 0x0f7e, X, CpuMMX, NoSuf|IgnoreSize|Modrm, { RegMMX, Reg32|Reg64|LongMem, 0 } }, -{"movd", 2, 0x660f6e,X,CpuSSE2,NoSuf|IgnoreSize|Modrm, { Reg32|Reg64|LLongMem, RegXMM, 0 } }, -{"movd", 2, 0x660f7e,X,CpuSSE2,NoSuf|IgnoreSize|Modrm, { RegXMM, Reg32|Reg64|LLongMem, 0 } }, +{"movd", 2, 0x660f6e,X,CpuSSE2,NoSuf|IgnoreSize|Modrm, { Reg32|Reg64|LongMem, RegXMM, 0 } }, +{"movd", 2, 0x660f7e,X,CpuSSE2,NoSuf|IgnoreSize|Modrm, { RegXMM, Reg32|Reg64|LongMem, 0 } }, /* In the 64bit mode the short form mov immediate is redefined to have 64bit displacement value. */ -{"movq", 2, 0x0f6f, X, CpuMMX, NoSuf|IgnoreSize|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, -{"movq", 2, 0x0f7f, X, CpuMMX, NoSuf|IgnoreSize|Modrm, { RegMMX, RegMMX|LongMem, 0 } }, -{"movq", 2, 0xf30f7e,X,CpuSSE2,NoSuf|IgnoreSize|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, -{"movq", 2, 0x660fd6,X,CpuSSE2,NoSuf|IgnoreSize|Modrm, { RegXMM, RegXMM|LLongMem, 0 } }, +{"movq", 2, 0x0f6f, X, CpuMMX, NoSuf|IgnoreSize|Modrm|NoRex64, { RegMMX|LLongMem, RegMMX, 0 } }, +{"movq", 2, 0x0f7f, X, CpuMMX, NoSuf|IgnoreSize|Modrm|NoRex64, { RegMMX, RegMMX|LLongMem, 0 } }, +{"movq", 2, 0xf30f7e,X,CpuSSE2,NoSuf|IgnoreSize|Modrm|NoRex64, { RegXMM|LLongMem, RegXMM, 0 } }, +{"movq", 2, 0x660fd6,X,CpuSSE2,NoSuf|IgnoreSize|Modrm|NoRex64, { RegXMM, RegXMM|LLongMem, 0 } }, +{"movq", 2, 0x0f6e, X, Cpu64, NoSuf|IgnoreSize|Modrm, { Reg64|LLongMem, RegMMX, 0 } }, +{"movq", 2, 0x0f7e, X, Cpu64, NoSuf|IgnoreSize|Modrm, { RegMMX, Reg64|LLongMem, 0 } }, +{"movq", 2, 0x660f6e,X,Cpu64, NoSuf|IgnoreSize|Modrm, { Reg64|LLongMem, RegXMM, 0 } }, +{"movq", 2, 0x660f7e,X,Cpu64, NoSuf|IgnoreSize|Modrm, { RegXMM, Reg64|LLongMem, 0 } }, /* We put the 64bit displacement first and we only mark constants larger than 32bit as Disp64. */ {"movq", 2, 0xa0, X, Cpu64, NoSuf|D|W|Size64, { Disp64, Acc, 0 } },