feat(amd64): encode the GOROOT instruction families
Assisted-by: DeepSeek V4.1 Flash
This commit is contained in:
+35
-18
@@ -180,10 +180,19 @@ var evexTable = map[string]evexSpec{
|
||||
"VPCMPUQ": {3, 0x1E, 1, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.66.0F38, permutes (NDS form).
|
||||
"VPERMB": {2, 0x8D, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMW": {2, 0x8D, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMI2D": {2, 0x76, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMI2Q": {2, 0x76, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMB": {2, 0x8D, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMW": {2, 0x8D, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMI2B": {2, 0x75, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMI2D": {2, 0x76, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMI2Q": {2, 0x76, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
// EVEX.66.0F38, population count (reg=dst, rm=src; W selects byte/word
|
||||
// against dword/qword).
|
||||
"VPOPCNTB": {2, 0x54, 0, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VPOPCNTD": {2, 0x55, 0, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VPOPCNTQ": {2, 0x55, 1, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
// EVEX.66.0F.W1, the qword spelling of the packed OR (VPORQ has no VEX
|
||||
// form in the Go assembler: it always encodes through EVEX).
|
||||
"VPORQ": {1, 0xEB, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMT2D": {2, 0x7E, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMT2Q": {2, 0x7E, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMT2PD": {2, 0x7F, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
@@ -1435,18 +1444,20 @@ var evexKOperand = map[string]bool{
|
||||
}
|
||||
|
||||
// kmovSpec describes a KMOV width: the opcode depends on the operand
|
||||
// direction, kk (k/mem → K is 90, k → k uses the same), kmem (K → mem),
|
||||
// gprk (GPR/mem → K), kgpr (K → GPR), and the GPR forms carry a mandatory
|
||||
// prefix and W for the wider widths.
|
||||
// direction, kk (k → k), kmem (k → mem), gprk (GPR/mem → k) and kgpr
|
||||
// (k → GPR). Each direction group carries its own mandatory prefix and W:
|
||||
// the k-destination/source forms share one pair, the GPR forms another.
|
||||
type kmovSpec struct {
|
||||
kk, kmem, gprk, kgpr byte
|
||||
gprPP int
|
||||
w int
|
||||
kPP, kW int // prefix and VEX.W for the k forms
|
||||
gprPP, gprW int // prefix and VEX.W for the GPR forms
|
||||
}
|
||||
|
||||
var kmovTable = map[string]kmovSpec{
|
||||
"KMOVW": {0x90, 0x91, 0x92, 0x93, 0, 0},
|
||||
"KMOVQ": {0x90, 0x91, 0x92, 0x93, 3, 1},
|
||||
"KMOVW": {0x90, 0x91, 0x92, 0x93, 0, 0, 0, 0},
|
||||
"KMOVB": {0x90, 0x91, 0x92, 0x93, 1, 0, 1, 0},
|
||||
"KMOVD": {0x90, 0x91, 0x92, 0x93, 1, 1, 3, 0},
|
||||
"KMOVQ": {0x90, 0x91, 0x92, 0x93, 0, 1, 3, 1},
|
||||
}
|
||||
|
||||
// encodeKmov encodes a KMOV width, selecting the opcode by direction.
|
||||
@@ -1460,14 +1471,14 @@ func (e *enc) encodeKmov(upper string, ops []Operand) error {
|
||||
dstReg, dstIsReg := dst.(Reg)
|
||||
srcK := srcIsReg && srcReg.mask
|
||||
dstK := dstIsReg && dstReg.mask
|
||||
spec := vexSpec{mapSel: 1, w: ks.w, pp: 0, opdigit: -1}
|
||||
switch {
|
||||
case srcK && dstK:
|
||||
spec.opcode = ks.kk // k ← k: reg = dst, rm = src
|
||||
// k ← k: reg = dst, rm = src.
|
||||
spec := vexSpec{mapSel: 1, opcode: ks.kk, w: ks.kW, pp: ks.kPP, opdigit: -1}
|
||||
return e.emitVexFields(spec, 0, dstReg.idx&7, 0, 15, src)
|
||||
case srcK && dstIsReg:
|
||||
spec.opcode = ks.kgpr // GPR ← k: reg = dst, rm = src
|
||||
spec.pp = ks.gprPP
|
||||
// GPR ← k: reg = dst, rm = src.
|
||||
spec := vexSpec{mapSel: 1, opcode: ks.kgpr, w: ks.gprW, pp: ks.gprPP, opdigit: -1}
|
||||
rBit := 0
|
||||
if dstReg.idx >= 8 {
|
||||
rBit = 1
|
||||
@@ -1477,11 +1488,17 @@ func (e *enc) encodeKmov(upper string, ops []Operand) error {
|
||||
if _, ok := dst.(Mem); !ok {
|
||||
return fmt.Errorf("%s: invalid destination operand", upper)
|
||||
}
|
||||
spec.opcode = ks.kmem // mem ← k: reg = src, rm = dst
|
||||
// mem ← k: reg = src, rm = dst.
|
||||
spec := vexSpec{mapSel: 1, opcode: ks.kmem, w: ks.kW, pp: ks.kPP, opdigit: -1}
|
||||
return e.emitVexFields(spec, 0, srcReg.idx&7, 0, 15, dst)
|
||||
case dstK:
|
||||
spec.opcode = ks.gprk // k ← GPR/mem: reg = dst, rm = src
|
||||
spec.pp = ks.gprPP
|
||||
// k ← GPR: reg = dst, rm = src. A memory source shares the k ← k
|
||||
// opcode and prefix group (the ykmovb layout the Go assembler uses).
|
||||
opcode, w, pp := ks.gprk, ks.gprW, ks.gprPP
|
||||
if memOperand(src) {
|
||||
opcode, w, pp = ks.kk, ks.kW, ks.kPP
|
||||
}
|
||||
spec := vexSpec{mapSel: 1, opcode: opcode, w: w, pp: pp, opdigit: -1}
|
||||
return e.emitVexFields(spec, 0, dstReg.idx&7, 0, 15, src)
|
||||
}
|
||||
return fmt.Errorf("%s requires a K register operand", upper)
|
||||
|
||||
Reference in New Issue
Block a user