diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..30cf57e
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Ignored default folder with query files
+/queries/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/gasm-devkit.iml b/.idea/gasm-devkit.iml
new file mode 100644
index 0000000..7c421e3
--- /dev/null
+++ b/.idea/gasm-devkit.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..fa14643
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/asm/encode_test.go b/asm/encode_test.go
index cec3aa2..c041a75 100644
--- a/asm/encode_test.go
+++ b/asm/encode_test.go
@@ -369,3 +369,29 @@ func TestSSEShuffleGroundTruth(t *testing.T) {
}
}
}
+
+// TestMOVQXMMGroundTruth pins the SSE2 packed-quadword move encodings:
+// loads and register moves on F3 0F 7E, stores on 66 0F D6 — the forms
+// the GPR-move fallback silently corrupted.
+func TestMOVQXMMGroundTruth(t *testing.T) {
+ cases := []struct {
+ name string
+ mnem string
+ ops []Operand
+ want string
+ }{
+ {"MOVQ (DI),X0", "MOVQ", []Operand{Ptr(DI, 0, 8), vreg(t, "X0")}, "f30f7e07"},
+ {"MOVQ X1,X2", "MOVQ", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "f30f7ed1"},
+ {"MOVQ X0,(DI)", "MOVQ", []Operand{vreg(t, "X0"), Ptr(DI, 0, 8)}, "660fd607"},
+ }
+ for _, c := range cases {
+ code, err := Encode(c.mnem, c.ops...)
+ if err != nil {
+ t.Errorf("%s: %v", c.name, err)
+ continue
+ }
+ if got := fmt.Sprintf("%x", code); got != c.want {
+ t.Errorf("%s = %s, want %s", c.name, got, c.want)
+ }
+ }
+}
diff --git a/asm/instrs.go b/asm/instrs.go
index 6237f38..b963ddf 100644
--- a/asm/instrs.go
+++ b/asm/instrs.go
@@ -48,6 +48,31 @@ func (e *enc) encodeMov(ops []Operand, size int) error {
}
src, dst := ops[0], ops[1]
+ // MOVQ with an XMM operand is the SSE2 packed-quadword move, NOT a
+ // GPR move: mem→xmm and xmm↔xmm encode as F3 0F 7E (reg = dst),
+ // xmm→mem as 66 0F D6 (rm = xmm). A GPR-move fallback would
+ // silently emit REX.W 8B with the wrong operand meaning.
+ _, srcVec := vecReg(src)
+ dstReg, dstVec := vecReg(dst)
+ if srcVec || dstVec {
+ if dstVec {
+ i := &instr{prefix: 0xF3, opcode: []byte{0x0F, 0x7E}, modrm: -1, sib: -1}
+ if err := setRM(i, dstReg, src, 8); err != nil {
+ return err
+ }
+ return e.emit(i)
+ }
+ srcXMM, srcIsXMM := src.(Reg)
+ if !srcIsXMM || !srcXMM.isVec() {
+ return fmt.Errorf("MOVQ: store needs an XMM source")
+ }
+ i := &instr{prefix: 0x66, opcode: []byte{0x0F, 0xD6}, modrm: -1, sib: -1}
+ if err := setRM(i, srcXMM, dst, 8); err != nil {
+ return err
+ }
+ return e.emit(i)
+ }
+
dstReg, dstIsReg := dst.(Reg)
switch src := src.(type) {
case Reg: