feat(amd64): assemble the double-shift and static-SB operand shapes
Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -200,10 +200,60 @@ func TestUnary(t *testing.T) {
|
||||
func TestShift(t *testing.T) {
|
||||
checkSyntax(t, "shl rdx, 0x2", "SHLQ", Imm(2), DX)
|
||||
checkSyntax(t, "shl rdx, cl", "SHLQ", CL, DX)
|
||||
checkSyntax(t, "shl rdx, cl", "SHLQ", CX, DX)
|
||||
checkSyntax(t, "shl rdx, 0x1", "SHLQ", Imm(1), DX)
|
||||
checkSyntax(t, "sar rcx, 0x1f", "SARQ", Imm(31), CX)
|
||||
}
|
||||
|
||||
// TestDoubleShift pins the three-operand SHL/SHR form, which encodes as
|
||||
// SHLD/SHRD: go tool asm accepts it for SHL/SHR at W/L/Q widths and rejects
|
||||
// it for SAR, SAL, the rotates and the B width. The byte pins mirror the
|
||||
// oracle's objdump output (48 0f a4 fe 0d for the first case, and so on).
|
||||
func TestDoubleShift(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
mnem string
|
||||
ops []Operand
|
||||
want string // hex encoding
|
||||
}{
|
||||
{"SHLQ imm", "SHLQ", []Operand{Imm(0x0d), DI, SI}, "480fa4fe0d"},
|
||||
{"SHLQ CX high regs", "SHLQ", []Operand{CX, Reg{idx: 8, size: 8}, Reg{idx: 9, size: 8}}, "4d0fa5c1"},
|
||||
{"SHRQ imm", "SHRQ", []Operand{Imm(1), AX, CX}, "480facc101"},
|
||||
{"SHLW imm", "SHLW", []Operand{Imm(1), AX, CX}, "660fa4c101"},
|
||||
{"SHRD CL", "SHRQ", []Operand{CL, AX, CX}, "480fadc1"},
|
||||
{"SHLD imm high regs", "SHLQ", []Operand{Imm(2), Reg{idx: 10, size: 8}, Reg{idx: 11, size: 8}}, "4d0fa4d302"},
|
||||
{"SHRD imm max", "SHRQ", []Operand{Imm(63), Reg{idx: 9, size: 8}, Reg{idx: 15, size: 8}}, "4d0faccf3f"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
code, err := Encode(c.mnem, c.ops...)
|
||||
if err != nil {
|
||||
t.Errorf("%s: Encode: %v", c.name, err)
|
||||
continue
|
||||
}
|
||||
if got := hexCompact(code); got != c.want {
|
||||
t.Errorf("%s: bytes %s, want %s", c.name, got, c.want)
|
||||
}
|
||||
}
|
||||
// Rejected forms: the oracle rejects every one of these.
|
||||
rejected := []struct {
|
||||
name string
|
||||
mnem string
|
||||
ops []Operand
|
||||
}{
|
||||
{"SARQ three operands", "SARQ", []Operand{Imm(1), AX, CX}},
|
||||
{"SALQ three operands", "SALQ", []Operand{Imm(1), AX, CX}},
|
||||
{"ROLQ three operands", "ROLQ", []Operand{Imm(1), AX, CX}},
|
||||
{"SHLB three operands", "SHLB", []Operand{Imm(1), AL, CL}},
|
||||
{"SHRQ memory source", "SHRQ", []Operand{Imm(1), Ptr(AX, 0, 8), CX}},
|
||||
{"SHRQ ECX count", "SHRQ", []Operand{Reg{idx: 1, size: 4}, AX, CX}},
|
||||
}
|
||||
for _, c := range rejected {
|
||||
if _, err := Encode(c.mnem, c.ops...); err == nil {
|
||||
t.Errorf("%s: Encode succeeded, want rejection", c.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImul(t *testing.T) {
|
||||
checkSyntax(t, "imul rdx, rcx", "IMULQ", CX, DX)
|
||||
checkSyntax(t, "imul edx, edx, 0x3", "IMULL", Imm(3), DX, DX)
|
||||
@@ -277,6 +327,12 @@ func TestSSEMoveGroundTruth(t *testing.T) {
|
||||
{"MOVSD (SI),X1", "MOVSD", []Operand{Ptr(SI, 0, 8), vreg(t, "X1")}, "f20f100e", "MOVSD_XMM"},
|
||||
{"MOVSD X1,X2", "MOVSD", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "f20f10d1", "MOVSD_XMM"},
|
||||
{"MOVSS X3,(DI)", "MOVSS", []Operand{vreg(t, "X3"), Ptr(DI, 0, 4)}, "f30f111f", "MOVSS"},
|
||||
// Static-symbol (SB) references: the GOROOT crypto kernels load and
|
||||
// store octa constants by name (MOVOU bswapMask<>+0(SB), X0).
|
||||
{"MOVOU sym,X0", "MOVOU", []Operand{sbMem{size: 16, name: "bswapMask"}, vreg(t, "X0")}, "f30f6f0500000000", "MOVDQU"},
|
||||
{"MOVOU X0,sym+8", "MOVOU", []Operand{vreg(t, "X0"), sbMem{size: 16, name: "bswapMask", addend: 8}}, "f30f7f0500000000", "MOVDQU"},
|
||||
{"MOVO sym,X1", "MOVO", []Operand{sbMem{size: 16, name: "gcmPoly"}, vreg(t, "X1")}, "660f6f0d00000000", "MOVDQA"},
|
||||
{"MOVO X2,sym", "MOVO", []Operand{vreg(t, "X2"), sbMem{size: 16, name: "gcmPoly"}}, "660f7f1500000000", "MOVDQA"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
code, err := Encode(c.mnem, c.ops...)
|
||||
|
||||
Reference in New Issue
Block a user