cmd: update vendored x/arch

Update vendored x/arch repo to 9c1a596, to bring in the support of
AVX instructions in the disassembler.

Done by

cd GOROOT/src/cmd
go get golang.org/x/arch@master
go mod tidy
go mod vendor

Fixes #78065.

Change-Id: Ie37b9e1ac57f9c8617d2613de164874ed8cb3a8c
Reviewed-on: https://go-review.googlesource.com/c/go/+/781281
TryBot-Bypass: Cherry Mui <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Cherry Mui 2026-05-21 11:02:54 -04:00
parent 0db3804845
commit 8621461b26
11 changed files with 16375 additions and 7616 deletions

View file

@ -4,7 +4,7 @@ go 1.27
require (
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83
golang.org/x/arch v0.27.1-0.20260513003155-2ebc08890589
golang.org/x/arch v0.27.1-0.20260521044007-9c1a596a2c97
golang.org/x/build v0.0.0-20260122183339-3ba88df37c64
golang.org/x/mod v0.36.1-0.20260513122029-343ee60345a1
golang.org/x/sync v0.20.0

View file

@ -6,8 +6,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b h1:ogbOPx8
github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/arch v0.27.1-0.20260513003155-2ebc08890589 h1:vhLfA6kUzRvCYV5uFBJbdMndztX1STqGC8GmQJsuldY=
golang.org/x/arch v0.27.1-0.20260513003155-2ebc08890589/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
golang.org/x/arch v0.27.1-0.20260521044007-9c1a596a2c97 h1:OEbDVxixMxnrAI3whhcFkCb0rPrEHwxeSSUMdN0V414=
golang.org/x/arch v0.27.1-0.20260521044007-9c1a596a2c97/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
golang.org/x/build v0.0.0-20260122183339-3ba88df37c64 h1:BNhBATNmH/VtzGolB+ksQPPvn6ZyffiR8TmKenqNo+A=
golang.org/x/build v0.0.0-20260122183339-3ba88df37c64/go.mod h1:3QmSbNil8ZWqC94m80Glej1v8b92gYzPIQPTtSa0c+4=
golang.org/x/mod v0.36.1-0.20260513122029-343ee60345a1 h1:C0TwvxhsI0bHc1TbK4QEa5PCMrHiST7y/lpX4MVW3KM=

653
src/cmd/vendor/golang.org/x/arch/x86/x86asm/avx.go generated vendored Normal file
View file

@ -0,0 +1,653 @@
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x86asm
import (
"encoding/binary"
"errors"
)
// This file contains the handling of AVX instructions, based on
// tables (avx_tables.go) generated from the XED data.
//go:generate go run _gen/genavx.go -o avx_tables.go
// decodeAVX decodes AVX/AVX2/AVX-512 instructions.
// It is called from decode1 when a VEX or EVEX prefix is detected.
func decodeAVX(src []byte, pos int, vex Prefix, vexIndex int, inst Inst, mode int) (Inst, error) {
var vexP, vexL, vexW uint8
var mapSelect uint8
var vvvv uint8
var vexR, vexX, vexB uint8 // Inverted from VEX/EVEX
var evex bool
var evexR_prime, evexV_prime uint8 // Inverted
var evex_aaa, evex_z uint8
var evex_b uint8
vexR = 1
vexX = 1
vexB = 1 // Default to 1 (inactive inverted)
evexR_prime = 1
evexV_prime = 1
if vex == 0xC5 { // 2-byte VEX
b1 := uint8(inst.Prefix[vexIndex+1])
vexR = (b1 >> 7) & 1
vvvv = (b1 >> 3) & 0xF
vexL = (b1 >> 2) & 1
vexP = b1 & 3
mapSelect = 1 // 0F
} else if vex == 0xC4 { // 3-byte VEX
b1 := uint8(inst.Prefix[vexIndex+1])
b2 := uint8(inst.Prefix[vexIndex+2])
vexR = (b1 >> 7) & 1
vexX = (b1 >> 6) & 1
vexB = (b1 >> 5) & 1
mapSelect = b1 & 0x1F
vexW = (b2 >> 7) & 1
vvvv = (b2 >> 3) & 0xF
vexL = (b2 >> 2) & 1
vexP = b2 & 3
} else if vex == 0x62 { // EVEX
evex = true
b1 := uint8(inst.Prefix[vexIndex+1])
b2 := uint8(inst.Prefix[vexIndex+2])
b3 := uint8(inst.Prefix[vexIndex+3])
vexR = (b1 >> 7) & 1
vexX = (b1 >> 6) & 1
vexB = (b1 >> 5) & 1
evexR_prime = (b1 >> 4) & 1
mapSelect = b1 & 3
vexW = (b2 >> 7) & 1
vvvv = (b2 >> 3) & 0xF
vexP = b2 & 3
evex_z = (b3 >> 7) & 1
vexL = (b3 >> 5) & 3
evex_b = (b3 >> 4) & 1
evexV_prime = (b3 >> 3) & 1
evex_aaa = b3 & 7
}
_ = evex_z // TODO: use zeroing mask if needed for output
opbyte := src[pos]
pos++
var candidates []*avxOptab
switch mapSelect {
case 1:
candidates = avxMap0F[opbyte]
case 2:
candidates = avxMap0F38[opbyte]
case 3:
candidates = avxMap0F3A[opbyte]
}
if len(candidates) == 0 {
return inst, errors.New("unknown AVX Opcode")
}
var modrm uint8
var haveModRM bool
if pos < len(src) {
modrm = src[pos]
haveModRM = true
}
var match *avxOptab
for i := range candidates {
c := candidates[i]
if evex != c.evex {
continue
}
c_vexP := c.vexP
p_match := false
switch c_vexP {
case 0:
p_match = vexP == 0
case 1:
p_match = vexP == 1
case 2:
p_match = vexP == 3
case 3:
p_match = vexP == 2
}
if !p_match {
continue
}
match_vexL := vexL
if evex && evex_b != 0 && haveModRM && (modrm>>6) == 3 {
hasZmm := false
for j := range candidates {
if candidates[j].evex == c.evex && candidates[j].vexP == c.vexP && candidates[j].vexW == c.vexW && candidates[j].vexL == 2 {
hasZmm = true
break
}
}
if hasZmm {
match_vexL = 2
} else {
match_vexL = 0
}
}
if c.vexL != match_vexL {
continue
}
if c.vexW != vexW {
continue
}
if haveModRM {
mod := modrm >> 6
reg := (modrm >> 3) & 7
if c.opdigit != -1 && reg != uint8(c.opdigit) {
continue
}
if c.ismem == 1 && mod == 3 {
continue
}
if c.ismem == 0 && mod != 3 {
continue
}
}
match = c
break
}
if match == nil {
return Inst{Len: 1}, ErrUnrecognized
}
inst.Op = match.op
var mod, reg, rm uint8
var sib uint8
var haveSIB bool
var mem Mem
var addrMode = mode
if haveModRM {
mod = modrm >> 6
reg = (modrm >> 3) & 7
rm = modrm & 7
pos++
if mod != 3 && rm == 4 {
if pos >= len(src) {
return inst, errors.New("truncated")
}
sib = src[pos]
haveSIB = true
pos++
}
var disp int64
if mod == 0 && (rm == 5 || (haveSIB && (sib&7) == 5)) || mod == 2 {
if pos+4 > len(src) {
return inst, errors.New("truncated")
}
disp = int64(int32(binary.LittleEndian.Uint32(src[pos:])))
pos += 4
} else if mod == 1 {
if pos >= len(src) {
return inst, errors.New("truncated")
}
disp = int64(int8(src[pos]))
pos++
if evex && match.dispScale > 0 {
scale := match.dispScale
if evex_b != 0 && match.bcstScale > 0 {
scale = match.bcstScale
}
disp *= int64(scale)
}
}
mem.Disp = disp
if haveSIB {
scale := sib >> 6
index := (sib >> 3) & 7
base := sib & 7
if vexX == 0 {
index |= 8
}
if vexB == 0 {
base |= 8
}
mem.Scale = 1 << uint(scale)
if index != 4 {
mem.Index = baseRegForBits(addrMode) + Reg(index)
}
if base&7 != 5 || mod != 0 {
mem.Base = baseRegForBits(addrMode) + Reg(base)
}
} else {
if vexB == 0 {
rm |= 8
}
if mod != 3 {
if !(mod == 0 && rm&7 == 5) {
mem.Base = baseRegForBits(addrMode) + Reg(rm)
}
}
}
}
// Decode Args
for i, argType := range match.args {
if argType == argNone {
continue
}
var arg Arg
switch argType {
case argImm8:
if pos >= len(src) {
return inst, errors.New("truncated")
}
arg = Imm(src[pos])
pos++
case argImm8u:
if pos >= len(src) {
return inst, errors.New("truncated")
}
arg = Imm(src[pos])
pos++
case argXmm_SE, argYmm_SE:
if pos >= len(src) {
return inst, errors.New("truncated")
}
idx := (src[pos] >> 4) & 0xF
if argType == argXmm_SE {
arg = X0 + Reg(idx)
} else {
arg = Y0 + Reg(idx)
}
pos++
case argGPR_R, argGPR32_R, argGPR64_R:
idx := reg
if vexR == 0 {
idx |= 8
}
base := baseRegForBits(mode)
if argType == argGPR32_R {
base = EAX
} else if argType == argGPR64_R {
base = RAX
}
arg = base + Reg(idx)
case argGPR_N, argGPR32_N, argGPR64_N:
idx := ^vvvv & 15 // 1s complement
base := baseRegForBits(mode)
if argType == argGPR32_N {
base = EAX
} else if argType == argGPR64_N {
base = RAX
} else if vexW == 1 {
base = RAX
}
arg = base + Reg(idx)
case argGPR_B, argGPR32_B, argGPR64_B:
idx := rm
if vexB == 0 {
idx |= 8
}
base := baseRegForBits(mode)
if argType == argGPR32_B {
base = EAX
} else if argType == argGPR64_B {
base = RAX
}
arg = base + Reg(idx)
// VEX/EVEX encoding uses inverted bits for register specifiers (0 means bit is set).
case argXmm_R, argXmmEvex_R:
idx := reg
if vexR == 0 {
idx |= 8
}
if evex && evexR_prime == 0 {
idx |= 16
}
arg = X0 + Reg(idx)
case argXmm_B, argXmmEvex_B:
idx := rm
if vexB == 0 {
idx |= 8
}
if evex && vexX == 0 {
idx |= 16
}
arg = X0 + Reg(idx)
case argXmm_N, argXmmEvex_N:
idx := 15 - vvvv
if evex && evexV_prime == 0 {
idx |= 16
}
arg = X0 + Reg(idx)
case argYmm_R, argYmmEvex_R:
idx := reg
if vexR == 0 {
idx |= 8
}
if evex && evexR_prime == 0 {
idx |= 16
}
arg = Y0 + Reg(idx)
case argYmm_B, argYmmEvex_B:
idx := rm
if vexB == 0 {
idx |= 8
}
if evex && vexX == 0 {
idx |= 16
}
arg = Y0 + Reg(idx)
case argYmm_N, argYmmEvex_N:
idx := 15 - vvvv
if evex && evexV_prime == 0 {
idx |= 16
}
arg = Y0 + Reg(idx)
case argZmm_R:
vl := vexL
if evex && evex_b != 0 && match.ismem == 0 {
vl = 2 // RC / SAE implies 512-bit vector length
}
idx := reg
if vexR == 0 {
idx |= 8
}
if evexR_prime == 0 {
idx |= 16
}
if vl == 0 {
arg = X0 + Reg(idx)
} else if vl == 1 {
arg = Y0 + Reg(idx)
} else {
arg = Z0 + Reg(idx)
}
case argZmm_B:
vl := vexL
if evex && evex_b != 0 && match.ismem == 0 {
vl = 2
}
if match.ismem != 0 {
arg = mem
} else {
idx := rm
if vexB == 0 {
idx |= 8
}
if vexX == 0 {
idx |= 16
}
if vl == 0 {
arg = X0 + Reg(idx)
} else if vl == 1 {
arg = Y0 + Reg(idx)
} else {
arg = Z0 + Reg(idx)
}
}
case argZmm_N:
vl := vexL
if evex && evex_b != 0 && match.ismem == 0 {
vl = 2
}
idx := 15 - vvvv
if evexV_prime == 0 {
idx |= 16
}
if vl == 0 {
arg = X0 + Reg(idx)
} else if vl == 1 {
arg = Y0 + Reg(idx)
} else {
arg = Z0 + Reg(idx)
}
case argK_R:
arg = K0 + Reg(reg&7)
case argK_B:
arg = K0 + Reg(rm&7)
case argK_N:
arg = K0 + Reg((15-vvvv)&7)
case argKmask:
if evex_aaa != 0 {
arg = K0 + Reg(evex_aaa)
}
case argKnot0:
if evex_aaa == 0 {
return inst, errors.New("k0 mask not allowed")
}
arg = K0 + Reg(evex_aaa)
case argM:
arg = mem
}
if arg != nil {
inst.Args[i] = arg
}
}
n := 0
for i := range len(inst.Args) {
if inst.Args[i] != nil {
if n != i {
inst.Args[n] = inst.Args[i]
inst.Args[i] = nil
}
n++
}
}
inst.MemBytes = int(match.memBytes)
if inst.MemBytes == 0 && match.ismem != 0 && match.dispScale != 0 {
inst.MemBytes = int(match.dispScale)
}
if evex {
inst.Zeroing = evex_z != 0
if evex_b != 0 {
if match.bcstScale > 0 {
inst.Broadcast = true
inst.MemBytes = int(match.bcstScale)
} else if match.ismem == 0 {
inst.SAE = true
inst.Rounding = int8(vexL)
}
}
}
inst.Len = pos
if match.vsib && haveSIB {
fixVSIB(&inst, vexL, evex, evexV_prime, vexX, sib)
}
return inst, nil
}
// fixVSIB calculates the correct vector register size based on data and index element sizes.
func fixVSIB(inst *Inst, vexL uint8, evex bool, evexV_prime uint8, vexX uint8, sib uint8) {
var indexElemBits, dataElemBits int
switch inst.Op {
case VPGATHERDD, VGATHERDPS, VPSCATTERDD, VSCATTERDPS:
indexElemBits = 32
dataElemBits = 32
case VPGATHERDQ, VGATHERDPD, VPSCATTERDQ, VSCATTERDPD:
indexElemBits = 32
dataElemBits = 64
case VPGATHERQD, VGATHERQPS, VPSCATTERQD, VSCATTERQPS:
indexElemBits = 64
dataElemBits = 32
case VPGATHERQQ, VGATHERQPD, VPSCATTERQQ, VSCATTERQPD:
indexElemBits = 64
dataElemBits = 64
case VGATHERPF0DPS, VGATHERPF1DPS, VSCATTERPF0DPS, VSCATTERPF1DPS:
indexElemBits = 32
dataElemBits = 32
case VGATHERPF0DPD, VGATHERPF1DPD, VSCATTERPF0DPD, VSCATTERPF1DPD:
indexElemBits = 32
dataElemBits = 64
case VGATHERPF0QPS, VGATHERPF1QPS, VSCATTERPF0QPS, VSCATTERPF1QPS:
indexElemBits = 64
dataElemBits = 32
case VGATHERPF0QPD, VGATHERPF1QPD, VSCATTERPF0QPD, VSCATTERPF1QPD:
indexElemBits = 64
dataElemBits = 64
default:
return
}
maxBits := 128 << vexL
var destBits, indexVectorBits int
if indexElemBits > dataElemBits {
indexVectorBits = maxBits
numElements := indexVectorBits / indexElemBits
destBits = numElements * dataElemBits
} else if dataElemBits > indexElemBits {
destBits = maxBits
numElements := destBits / dataElemBits
indexVectorBits = numElements * indexElemBits
} else {
indexVectorBits = maxBits
destBits = maxBits
}
// Override MemBytes to match objdump's output expectation (memory accessed is based on dest size)
inst.MemBytes = destBits / 8
if indexVectorBits < 128 {
indexVectorBits = 128
}
var baseReg Reg
switch indexVectorBits {
case 128:
baseReg = X0
case 256:
baseReg = Y0
case 512:
baseReg = Z0
default:
baseReg = X0
}
for i, arg := range inst.Args {
if mem, ok := arg.(Mem); ok {
idx := (sib >> 3) & 7
if vexX == 0 {
idx |= 8
}
if evex && evexV_prime == 0 {
idx |= 16
}
mem.Index = baseReg + Reg(idx)
inst.Args[i] = mem
break
}
}
}
// argType defines how to decode an argument.
// It corresponds to the arg type notation in XED.
type argType uint8
const (
argNone argType = iota
argImm8
argImm8u
argImm16
argImm32
argImm64
// GPRs
argGPR_R // ModRM.reg (default mode size)
argGPR_B // ModRM.rm (default mode size)
argGPR_N // VEX.vvvv (default mode size)
argGPR32_R // ModRM.reg (32-bit forced)
argGPR32_B // ModRM.rm (32-bit forced)
argGPR32_N // VEX.vvvv (32-bit forced)
argGPR64_R // ModRM.reg (64-bit forced)
argGPR64_B // ModRM.rm (64-bit forced)
argGPR64_N // VEX.vvvv (64-bit forced)
// XMM
argXmm_R
argXmm_B
argXmm_N
argXmmEvex_R
argXmmEvex_B
argXmmEvex_N
argXmm_SE // is4 immediate
// YMM
argYmm_R
argYmm_B
argYmm_N
argYmmEvex_R
argYmmEvex_B
argYmmEvex_N
argYmm_SE
// ZMM
argZmm_R
argZmm_B
argZmm_N
// Mask
argK_R
argK_B
argK_N
argM // Memory operand (ModRM.rm)
argKnot0 // Mask register k1-k7
argKmask // Mask register k0-k7
)
// hasRC returns true if the instruction supports static rounding control in AVX-512.
func hasRC(op Op) bool {
switch op {
case VADDPD, VADDPS, VADDSD, VADDSS,
VSUBPD, VSUBPS, VSUBSD, VSUBSS,
VMULPD, VMULPS, VMULSD, VMULSS,
VDIVPD, VDIVPS, VDIVSD, VDIVSS,
VSQRTPD, VSQRTPS, VSQRTSD, VSQRTSS,
VSCALEFPD, VSCALEFPS, VSCALEFSD, VSCALEFSS,
VFMADD132PD, VFMADD132PS, VFMADD132SD, VFMADD132SS,
VFMADD213PD, VFMADD213PS, VFMADD213SD, VFMADD213SS,
VFMADD231PD, VFMADD231PS, VFMADD231SD, VFMADD231SS,
VFMSUB132PD, VFMSUB132PS, VFMSUB132SD, VFMSUB132SS,
VFMSUB213PD, VFMSUB213PS, VFMSUB213SD, VFMSUB213SS,
VFMSUB231PD, VFMSUB231PS, VFMSUB231SD, VFMSUB231SS,
VFNMADD132PD, VFNMADD132PS, VFNMADD132SD, VFNMADD132SS,
VFNMADD213PD, VFNMADD213PS, VFNMADD213SD, VFNMADD213SS,
VFNMADD231PD, VFNMADD231PS, VFNMADD231SD, VFNMADD231SS,
VFNMSUB132PD, VFNMSUB132PS, VFNMSUB132SD, VFNMSUB132SS,
VFNMSUB213PD, VFNMSUB213PS, VFNMSUB213SD, VFNMSUB213SS,
VFNMSUB231PD, VFNMSUB231PS, VFNMSUB231SD, VFNMSUB231SS,
VFMADDSUB132PD, VFMADDSUB132PS, VFMADDSUB213PD, VFMADDSUB213PS,
VFMADDSUB231PD, VFMADDSUB231PS, VFMSUBADD132PD, VFMSUBADD132PS,
VFMSUBADD213PD, VFMSUBADD213PS, VFMSUBADD231PD, VFMSUBADD231PS,
VCVTPS2DQ, VCVTPD2DQ, VCVTPS2UDQ, VCVTPD2UDQ,
VCVTPS2QQ, VCVTPD2QQ, VCVTPS2UQQ, VCVTPD2UQQ,
VCVTUDQ2PS, VCVTUDQ2PD, VCVTQQ2PS, VCVTQQ2PD,
VCVTUQQ2PS, VCVTUQQ2PD, VCVTDQ2PS, VCVTDQ2PD,
VCVTPS2PD, VCVTPD2PS, VCVTSS2SD, VCVTSD2SS,
VCVTUSI2SS, VCVTUSI2SD, VCVTSI2SS, VCVTSI2SD,
VCVTSS2USI, VCVTSD2USI, VCVTSS2SI, VCVTSD2SI,
VPERMT2PD, VPERMT2PS, VPERMI2PD, VPERMI2PS:
return true
}
return false
}

7382
src/cmd/vendor/golang.org/x/arch/x86/x86asm/avx_tables.go generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -405,15 +405,16 @@ ReadPrefixes:
}
addrSizeIndex = pos
//Group 5 - Vex encoding
// Group 5 - Vex encoding
case 0xC5:
if pos == 0 && pos+1 < len(src) && (mode == 64 || (mode == 32 && src[pos+1]&0xc0 == 0xc0)) {
vex = p
vexIndex = pos
inst.Prefix[pos] = p
inst.Prefix[pos+1] = Prefix(src[pos+1])
pos += 1
continue
pos += 2
nprefix = pos
break ReadPrefixes
} else {
nprefix = pos
break ReadPrefixes
@ -425,8 +426,25 @@ ReadPrefixes:
inst.Prefix[pos] = p
inst.Prefix[pos+1] = Prefix(src[pos+1])
inst.Prefix[pos+2] = Prefix(src[pos+2])
pos += 2
continue
pos += 3
nprefix = pos
break ReadPrefixes
} else {
nprefix = pos
break ReadPrefixes
}
// EVEX encoding
case 0x62:
if pos == 0 && pos+3 < len(src) && (mode == 64 || (mode == 32 && src[pos+1]&0xc0 == 0xc0)) {
vex = p
vexIndex = pos
inst.Prefix[pos] = p
inst.Prefix[pos+1] = Prefix(src[pos+1])
inst.Prefix[pos+2] = Prefix(src[pos+2])
inst.Prefix[pos+3] = Prefix(src[pos+3])
pos += 4
nprefix = pos
break ReadPrefixes
} else {
nprefix = pos
break ReadPrefixes
@ -462,6 +480,10 @@ ReadPrefixes:
// opcode byte into inst.Opcode.
opshift = 24
if vex != 0 {
return decodeAVX(src, pos, vex, vexIndex, inst, mode)
}
// Decode loop, executing decoder program.
var oldPC, prevPC int
Decode:

View file

@ -268,7 +268,7 @@ SuffixLoop:
}
}
if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= X15 || M0 <= a && a <= M7 {
if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= Z31 || M0 <= a && a <= M7 || K0 <= a && a <= K7 {
needSuffix = false
break SuffixLoop
}
@ -279,7 +279,7 @@ SuffixLoop:
switch inst.Op {
case CMPXCHG8B, FLDCW, FNSTCW, FNSTSW, LDMXCSR, LLDT, LMSW, LTR, PCLMULQDQ,
SETA, SETAE, SETB, SETBE, SETE, SETG, SETGE, SETL, SETLE, SETNE, SETNO, SETNP, SETNS, SETO, SETP, SETS,
SLDT, SMSW, STMXCSR, STR, VERR, VERW:
SLDT, SMSW, STMXCSR, STR, VERR, VERW, VLDMXCSR, VSTMXCSR:
// For various reasons, libopcodes emits no suffix for these instructions.
case CRC32:
@ -354,6 +354,74 @@ SuffixLoop:
}
}
isVexOrEvex := false
for _, p := range inst.Prefix {
if p.IsVEX() || p&0xFF == 0x62 {
isVexOrEvex = true
break
}
}
if isVexOrEvex {
hasMem := false
for _, a := range inst.Args {
if _, ok := a.(Mem); ok {
hasMem = true
break
}
}
if hasMem {
if inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTTPD2DQ || inst.Op == VCVTTPD2UDQ || inst.Op == VCVTTPD2QQ || inst.Op == VCVTTPD2UQQ || inst.Op == VCVTPD2DQ || inst.Op == VCVTPD2UDQ || inst.Op == VCVTPD2QQ || inst.Op == VCVTPD2UQQ || inst.Op == VCVTPD2PS {
vexL := 0
isEvex := false
for i, p := range inst.Prefix {
if p.IsEVEX() && i+3 < len(inst.Prefix) && inst.Prefix[i+3] != 0 {
vexL = int((inst.Prefix[i+3]&0xFF)>>5) & 3
isEvex = true
break
} else if p.IsVEX() && i+2 < len(inst.Prefix) {
if p&0xFF == 0xC4 {
vexL = int((inst.Prefix[i+2]&0xFF)>>2) & 1
} else if p&0xFF == 0xC5 {
vexL = int((inst.Prefix[i+1]&0xFF)>>2) & 1
}
break
}
}
if !isEvex || inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTPD2DQ {
switch vexL {
case 0:
op += "x"
case 1:
if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
op += "y"
}
case 2:
if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
op += "z"
}
}
}
} else if inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS {
is64 := false
if (inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS) && inst.MemBytes == 8 {
is64 = true
} else {
for _, a := range inst.Args {
if r, ok := a.(Reg); ok && RAX <= r && r <= R15 {
is64 = true
break
}
}
}
if is64 {
op += "q"
} else {
op += "l"
}
}
}
}
// Adjust special case opcodes.
switch inst.Op {
case 0:
@ -374,6 +442,20 @@ SuffixLoop:
op = cmppsOps[imm] + op[3:]
}
case VCMPPD, VCMPPS, VCMPSD, VCMPSS, VCMPPH, VCMPSH, VCMPBF16:
for i := len(inst.Args) - 1; i >= 0; i-- {
if imm, ok := inst.Args[i].(Imm); ok {
if 0 <= imm && imm < 8 {
inst.Args[i] = nil
op = "v" + cmppsOps[imm] + op[4:]
}
break
}
if inst.Args[i] != nil {
break
}
}
case PCLMULQDQ:
imm, ok := inst.Args[2].(Imm)
if ok && imm&^0x11 == 0 {
@ -407,7 +489,64 @@ SuffixLoop:
if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
continue
}
args = append(args, gnuArg(&inst, pc, symname, a, &usedPrefixes))
argStr := gnuArg(&inst, pc, symname, a, &usedPrefixes)
if i == 1 {
r, ok := a.(Reg)
// In GNU syntax, the mask register usually appears as the second argument (index 1).
if ok && K1 <= r && r <= K7 {
if !strings.HasPrefix(inst.Op.String(), "K") {
if len(args) > 0 {
args[0] += fmt.Sprintf(" {%s}", argStr)
if inst.Zeroing {
args[0] += " {z}"
}
}
continue
}
} else if ok && r == K0 {
if !strings.HasPrefix(inst.Op.String(), "K") {
if inst.Zeroing && len(args) > 0 {
args[0] += "{z}"
}
continue
}
}
}
if _, ok := a.(Mem); ok && inst.Broadcast && len(args) > 0 {
if dstReg, ok := inst.Args[0].(Reg); ok {
var vBytes int
if X0 <= dstReg && dstReg <= X31 {
vBytes = 16
} else if Y0 <= dstReg && dstReg <= Y31 {
vBytes = 32
} else if Z0 <= dstReg && dstReg <= Z31 {
vBytes = 64
}
if vBytes > 0 && inst.MemBytes > 0 {
argStr += fmt.Sprintf("{1to%d}", vBytes/inst.MemBytes)
}
}
}
args = append(args, argStr)
}
if inst.SAE {
var sae string
if hasRC(inst.Op) {
switch inst.Rounding {
case 0:
sae = "{rn-sae}"
case 1:
sae = "{rd-sae}"
case 2:
sae = "{ru-sae}"
case 3:
sae = "{rz-sae}"
}
} else {
sae = "{sae}"
}
args = append(args, sae)
}
// The default is to print the arguments in reverse Intel order.
@ -436,7 +575,7 @@ SuffixLoop:
}
}
for _, p := range inst.Prefix {
if p == 0 || p.IsVEX() {
if p == 0 || p.IsVEX() || p.IsEVEX() {
break
}
if p&PrefixImplicit != 0 {
@ -534,8 +673,6 @@ func gnuArg(inst *Inst, pc uint64, symname SymLookup, x Arg, usedPrefixes *bool)
if x == DX {
return "(%dx)"
}
case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
return strings.Replace(gccRegName[x], "xmm", "ymm", -1)
}
return gccRegName[x]
case Mem:
@ -566,6 +703,10 @@ func gnuArg(inst *Inst, pc uint64, symname SymLookup, x Arg, usedPrefixes *bool)
case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ:
// These do not accept segment prefixes, at least in the GNU rendering.
default:
if isVSIB(inst.Op) {
haveCS, haveDS, haveES, haveSS = false, false, false, false
break
}
if *usedPrefixes {
break
}
@ -653,6 +794,14 @@ func gnuArg(inst *Inst, pc uint64, symname SymLookup, x Arg, usedPrefixes *bool)
// 16-bit addressing - no scale
return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
}
if x.Scale == 1 {
// Special case to match objdump output for explicit scale 1.
// XXX is this the only one?
if inst.Op.String() == "VMOVNTDQA" {
return fmt.Sprintf("%s%s(%s,%s,1)", seg, disp, base, index)
}
return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
}
return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
case Rel:
if pc == 0 {
@ -789,6 +938,94 @@ var gccRegName = [...]string{
X13: "%xmm13",
X14: "%xmm14",
X15: "%xmm15",
X16: "%xmm16",
X17: "%xmm17",
X18: "%xmm18",
X19: "%xmm19",
X20: "%xmm20",
X21: "%xmm21",
X22: "%xmm22",
X23: "%xmm23",
X24: "%xmm24",
X25: "%xmm25",
X26: "%xmm26",
X27: "%xmm27",
X28: "%xmm28",
X29: "%xmm29",
X30: "%xmm30",
X31: "%xmm31",
Y0: "%ymm0",
Y1: "%ymm1",
Y2: "%ymm2",
Y3: "%ymm3",
Y4: "%ymm4",
Y5: "%ymm5",
Y6: "%ymm6",
Y7: "%ymm7",
Y8: "%ymm8",
Y9: "%ymm9",
Y10: "%ymm10",
Y11: "%ymm11",
Y12: "%ymm12",
Y13: "%ymm13",
Y14: "%ymm14",
Y15: "%ymm15",
Y16: "%ymm16",
Y17: "%ymm17",
Y18: "%ymm18",
Y19: "%ymm19",
Y20: "%ymm20",
Y21: "%ymm21",
Y22: "%ymm22",
Y23: "%ymm23",
Y24: "%ymm24",
Y25: "%ymm25",
Y26: "%ymm26",
Y27: "%ymm27",
Y28: "%ymm28",
Y29: "%ymm29",
Y30: "%ymm30",
Y31: "%ymm31",
Z0: "%zmm0",
Z1: "%zmm1",
Z2: "%zmm2",
Z3: "%zmm3",
Z4: "%zmm4",
Z5: "%zmm5",
Z6: "%zmm6",
Z7: "%zmm7",
Z8: "%zmm8",
Z9: "%zmm9",
Z10: "%zmm10",
Z11: "%zmm11",
Z12: "%zmm12",
Z13: "%zmm13",
Z14: "%zmm14",
Z15: "%zmm15",
Z16: "%zmm16",
Z17: "%zmm17",
Z18: "%zmm18",
Z19: "%zmm19",
Z20: "%zmm20",
Z21: "%zmm21",
Z22: "%zmm22",
Z23: "%zmm23",
Z24: "%zmm24",
Z25: "%zmm25",
Z26: "%zmm26",
Z27: "%zmm27",
Z28: "%zmm28",
Z29: "%zmm29",
Z30: "%zmm30",
Z31: "%zmm31",
K0: "%k0",
K1: "%k1",
K2: "%k2",
K3: "%k3",
K4: "%k4",
K5: "%k5",
K6: "%k6",
K7: "%k7",
CS: "%cs",
SS: "%ss",
DS: "%ds",

View file

@ -23,6 +23,11 @@ type Inst struct {
Len int // length of encoded instruction in bytes
PCRel int // length of PC-relative address in instruction encoding
PCRelOff int // index of start of PC-relative address in instruction encoding
// AVX-512 flags
Broadcast bool // EVEX broadcast
Zeroing bool // EVEX zeroing
SAE bool // Suppress All Exceptions
Rounding int8 // Rounding control (0-3), valid only when SAE is true
}
// Prefixes is an array of prefixes associated with a single instruction.
@ -79,6 +84,7 @@ const (
PrefixREXB Prefix = 0x01 // extension bit B (r/m field in modrm or base field in sib)
PrefixVEX2Bytes Prefix = 0xC5 // Short form of vex prefix
PrefixVEX3Bytes Prefix = 0xC4 // Long form of vex prefix
PrefixEVEX Prefix = 0x62 // EVEX prefix
)
// IsREX reports whether p is a REX prefix byte.
@ -90,6 +96,10 @@ func (p Prefix) IsVEX() bool {
return p&0xFF == PrefixVEX2Bytes || p&0xFF == PrefixVEX3Bytes
}
func (p Prefix) IsEVEX() bool {
return p&0xFF == PrefixEVEX
}
func (p Prefix) String() string {
p &^= PrefixImplicit | PrefixIgnored | PrefixInvalid
if s := prefixNames[p]; s != "" {
@ -122,6 +132,9 @@ type Op uint32
func (op Op) String() string {
i := int(op)
if i < 0 || i >= len(opNames) || opNames[i] == "" {
if i < len(avxOpNames) && avxOpNames[i] != "" {
return avxOpNames[i]
}
return fmt.Sprintf("Op(%d)", i)
}
return opNames[i]
@ -130,7 +143,7 @@ func (op Op) String() string {
// An Args holds the instruction arguments.
// If an instruction has fewer than 4 arguments,
// the final elements in the array are nil.
type Args [4]Arg
type Args [6]Arg
// An Arg is a single instruction argument,
// one of these types: Reg, Mem, Imm, Rel.
@ -268,6 +281,100 @@ const (
X13
X14
X15
X16
X17
X18
X19
X20
X21
X22
X23
X24
X25
X26
X27
X28
X29
X30
X31
// YMM registers.
Y0
Y1
Y2
Y3
Y4
Y5
Y6
Y7
Y8
Y9
Y10
Y11
Y12
Y13
Y14
Y15
Y16
Y17
Y18
Y19
Y20
Y21
Y22
Y23
Y24
Y25
Y26
Y27
Y28
Y29
Y30
Y31
// ZMM registers.
Z0
Z1
Z2
Z3
Z4
Z5
Z6
Z7
Z8
Z9
Z10
Z11
Z12
Z13
Z14
Z15
Z16
Z17
Z18
Z19
Z20
Z21
Z22
Z23
Z24
Z25
Z26
Z27
Z28
Z29
Z30
Z31
// Mask registers.
K0
K1
K2
K3
K4
K5
K6
K7
// Segment registers.
ES
@ -595,6 +702,94 @@ var regNames = [...]string{
X13: "X13",
X14: "X14",
X15: "X15",
X16: "X16",
X17: "X17",
X18: "X18",
X19: "X19",
X20: "X20",
X21: "X21",
X22: "X22",
X23: "X23",
X24: "X24",
X25: "X25",
X26: "X26",
X27: "X27",
X28: "X28",
X29: "X29",
X30: "X30",
X31: "X31",
Y0: "Y0",
Y1: "Y1",
Y2: "Y2",
Y3: "Y3",
Y4: "Y4",
Y5: "Y5",
Y6: "Y6",
Y7: "Y7",
Y8: "Y8",
Y9: "Y9",
Y10: "Y10",
Y11: "Y11",
Y12: "Y12",
Y13: "Y13",
Y14: "Y14",
Y15: "Y15",
Y16: "Y16",
Y17: "Y17",
Y18: "Y18",
Y19: "Y19",
Y20: "Y20",
Y21: "Y21",
Y22: "Y22",
Y23: "Y23",
Y24: "Y24",
Y25: "Y25",
Y26: "Y26",
Y27: "Y27",
Y28: "Y28",
Y29: "Y29",
Y30: "Y30",
Y31: "Y31",
Z0: "Z0",
Z1: "Z1",
Z2: "Z2",
Z3: "Z3",
Z4: "Z4",
Z5: "Z5",
Z6: "Z6",
Z7: "Z7",
Z8: "Z8",
Z9: "Z9",
Z10: "Z10",
Z11: "Z11",
Z12: "Z12",
Z13: "Z13",
Z14: "Z14",
Z15: "Z15",
Z16: "Z16",
Z17: "Z17",
Z18: "Z18",
Z19: "Z19",
Z20: "Z20",
Z21: "Z21",
Z22: "Z22",
Z23: "Z23",
Z24: "Z24",
Z25: "Z25",
Z26: "Z26",
Z27: "Z27",
Z28: "Z28",
Z29: "Z29",
Z30: "Z30",
Z31: "Z31",
K0: "K0",
K1: "K1",
K2: "K2",
K3: "K3",
K4: "K4",
K5: "K5",
K6: "K6",
K7: "K7",
CS: "CS",
SS: "SS",
DS: "DS",

View file

@ -99,6 +99,12 @@ func IntelSyntax(inst Inst, pc uint64, symname SymLookup) string {
inst.Prefix[i] |= PrefixImplicit
inst.Prefix[i+1] |= PrefixImplicit
}
if p.IsEVEX() {
inst.Prefix[i] |= PrefixImplicit
inst.Prefix[i+1] |= PrefixImplicit
inst.Prefix[i+2] |= PrefixImplicit
inst.Prefix[i+3] |= PrefixImplicit
}
}
}
@ -256,11 +262,55 @@ func IntelSyntax(inst Inst, pc uint64, symname SymLookup) string {
}
var args []string
for _, a := range iargs {
for i, a := range iargs {
if a == nil {
break
}
args = append(args, intelArg(&inst, pc, symname, a))
argStr := intelArg(&inst, pc, symname, a)
if i == 1 {
r, ok := a.(Reg)
if ok && K1 <= r && r <= K7 {
if !strings.HasPrefix(inst.Op.String(), "K") {
isPF := strings.HasPrefix(inst.Op.String(), "VGATHERPF") || strings.HasPrefix(inst.Op.String(), "VSCATTERPF")
if isPF {
args = append([]string{fmt.Sprintf("{%s}", argStr)}, args...)
} else if len(args) > 0 {
args[len(args)-1] += fmt.Sprintf(" {%s}", argStr)
if inst.Zeroing {
args[len(args)-1] += " {z}"
}
}
continue
}
} else if ok && r == K0 {
if !strings.HasPrefix(inst.Op.String(), "K") {
isPF := strings.HasPrefix(inst.Op.String(), "VGATHERPF") || strings.HasPrefix(inst.Op.String(), "VSCATTERPF")
if isPF {
args = append([]string{fmt.Sprintf("{%s}", argStr)}, args...)
} else if inst.Zeroing && len(args) > 0 {
args[len(args)-1] += " {z}"
}
continue
}
}
}
if _, ok := a.(Mem); ok && inst.Broadcast && len(args) > 0 {
// Find vector size from first argument (destination)
if dstReg, ok := iargs[0].(Reg); ok {
var vBytes int
if X0 <= dstReg && dstReg <= X31 {
vBytes = 16
} else if Y0 <= dstReg && dstReg <= Y31 {
vBytes = 32
} else if Z0 <= dstReg && dstReg <= Z31 {
vBytes = 64
}
if vBytes > 0 && inst.MemBytes > 0 {
argStr += fmt.Sprintf("{1to%d}", vBytes/inst.MemBytes)
}
}
}
args = append(args, argStr)
}
var op string
@ -288,6 +338,24 @@ func IntelSyntax(inst Inst, pc uint64, symname SymLookup) string {
args[0], args[1] = args[1], args[0]
}
case VCMPPD, VCMPPS, VCMPSD, VCMPSS, VCMPPH, VCMPSH, VCMPBF16:
for i := len(inst.Args) - 1; i >= 0; i-- {
if imm, ok := inst.Args[i].(Imm); ok {
if 0 <= imm && imm < 8 {
args = args[:len(args)-1]
baseOp := intelOp[inst.Op]
if baseOp == "" {
baseOp = strings.ToLower(inst.Op.String())
}
op = "v" + cmppsOps[imm] + baseOp[4:]
}
break
}
if inst.Args[i] != nil {
break
}
}
case FCHS, FABS, FTST, FLDPI, FLDL2E, FLDLG2, F2XM1, FXAM, FLD1, FLDL2T, FSQRT, FRNDINT, FCOS, FSIN:
if len(args) == 0 {
args = append(args, "st0")
@ -326,6 +394,23 @@ func IntelSyntax(inst Inst, pc uint64, symname SymLookup) string {
}
}
if inst.SAE {
if hasRC(inst.Op) {
switch inst.Rounding {
case 0:
args = append(args, "{rn-sae}")
case 1:
args = append(args, "{rd-sae}")
case 2:
args = append(args, "{ru-sae}")
case 3:
args = append(args, "{rz-sae}")
}
} else {
args = append(args, "{sae}")
}
}
if op == "" {
op = intelOp[inst.Op]
}
@ -375,6 +460,16 @@ func intelArg(inst *Inst, pc uint64, symname SymLookup, arg Arg) string {
prefix = "xmmword "
case 32:
prefix = "ymmword "
case 64:
prefix = "zmmword "
}
if isVSIB(inst.Op) {
switch inst.Op {
case VPGATHERDD, VPSCATTERDD, VPGATHERQD, VPSCATTERQD, VGATHERDPS, VSCATTERDPS, VGATHERQPS, VSCATTERQPS, VGATHERPF0DPS, VGATHERPF1DPS, VSCATTERPF0DPS, VSCATTERPF1DPS, VGATHERPF0QPS, VGATHERPF1QPS, VSCATTERPF0QPS, VSCATTERPF1QPS:
prefix = "dword "
case VPGATHERDQ, VPSCATTERDQ, VPGATHERQQ, VPSCATTERQQ, VGATHERDPD, VSCATTERDPD, VGATHERQPD, VSCATTERQPD, VGATHERPF0DPD, VGATHERPF1DPD, VSCATTERPF0DPD, VSCATTERPF1DPD, VGATHERPF0QPD, VGATHERPF1QPD, VSCATTERPF0QPD, VSCATTERPF1QPD:
prefix = "qword "
}
}
switch inst.Op {
case INVLPG:
@ -448,7 +543,17 @@ func intelArg(inst *Inst, pc uint64, symname SymLookup, arg Arg) string {
if a.Base != 0 {
prefix += "+"
}
prefix += fmt.Sprintf("%s*%d", intelArg(inst, pc, symname, a.Index), a.Scale)
if a.Scale == 1 {
if inst.AddrSize == 16 || inst.Op.String() == "VMOVNTDQA" {
prefix += fmt.Sprintf("%s*1", intelArg(inst, pc, symname, a.Index))
} else if a.Base == 0 && ((X0 <= a.Index && a.Index <= Z31) || (M0 <= a.Index && a.Index <= M7)) {
prefix += fmt.Sprintf("1*%s", intelArg(inst, pc, symname, a.Index))
} else {
prefix += fmt.Sprintf("%s", intelArg(inst, pc, symname, a.Index))
}
} else {
prefix += fmt.Sprintf("%d*%s", a.Scale, intelArg(inst, pc, symname, a.Index))
}
}
if a.Disp != 0 {
if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
@ -473,12 +578,7 @@ func intelArg(inst *Inst, pc uint64, symname SymLookup, arg Arg) string {
}
case Reg:
if int(a) < len(intelReg) && intelReg[a] != "" {
switch inst.Op {
case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
return strings.Replace(intelReg[a], "xmm", "ymm", -1)
default:
return intelReg[a]
}
return intelReg[a]
}
}
return strings.ToLower(arg.String())
@ -544,6 +644,94 @@ var intelReg = [...]string{
X13: "xmm13",
X14: "xmm14",
X15: "xmm15",
X16: "xmm16",
X17: "xmm17",
X18: "xmm18",
X19: "xmm19",
X20: "xmm20",
X21: "xmm21",
X22: "xmm22",
X23: "xmm23",
X24: "xmm24",
X25: "xmm25",
X26: "xmm26",
X27: "xmm27",
X28: "xmm28",
X29: "xmm29",
X30: "xmm30",
X31: "xmm31",
Y0: "ymm0",
Y1: "ymm1",
Y2: "ymm2",
Y3: "ymm3",
Y4: "ymm4",
Y5: "ymm5",
Y6: "ymm6",
Y7: "ymm7",
Y8: "ymm8",
Y9: "ymm9",
Y10: "ymm10",
Y11: "ymm11",
Y12: "ymm12",
Y13: "ymm13",
Y14: "ymm14",
Y15: "ymm15",
Y16: "ymm16",
Y17: "ymm17",
Y18: "ymm18",
Y19: "ymm19",
Y20: "ymm20",
Y21: "ymm21",
Y22: "ymm22",
Y23: "ymm23",
Y24: "ymm24",
Y25: "ymm25",
Y26: "ymm26",
Y27: "ymm27",
Y28: "ymm28",
Y29: "ymm29",
Y30: "ymm30",
Y31: "ymm31",
Z0: "zmm0",
Z1: "zmm1",
Z2: "zmm2",
Z3: "zmm3",
Z4: "zmm4",
Z5: "zmm5",
Z6: "zmm6",
Z7: "zmm7",
Z8: "zmm8",
Z9: "zmm9",
Z10: "zmm10",
Z11: "zmm11",
Z12: "zmm12",
Z13: "zmm13",
Z14: "zmm14",
Z15: "zmm15",
Z16: "zmm16",
Z17: "zmm17",
Z18: "zmm18",
Z19: "zmm19",
Z20: "zmm20",
Z21: "zmm21",
Z22: "zmm22",
Z23: "zmm23",
Z24: "zmm24",
Z25: "zmm25",
Z26: "zmm26",
Z27: "zmm27",
Z28: "zmm28",
Z29: "zmm29",
Z30: "zmm30",
Z31: "zmm31",
K0: "k0",
K1: "k1",
K2: "k2",
K3: "k3",
K4: "k4",
K5: "k5",
K6: "k6",
K7: "k7",
// TODO: Maybe the constants are named wrong.
SPB: "spl",

View file

@ -34,7 +34,7 @@ func GoSyntax(inst Inst, pc uint64, symname SymLookup) string {
var rep string
var last Prefix
for _, p := range inst.Prefix {
if p == 0 || p.IsREX() || p.IsVEX() {
if p == 0 || p.IsREX() || p.IsVEX() || p.IsEVEX() {
break
}
@ -62,7 +62,61 @@ func GoSyntax(inst Inst, pc uint64, symname SymLookup) string {
}
op := inst.Op.String()
if plan9Suffix[inst.Op] {
if inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTTPD2DQ || inst.Op == VCVTTPD2UDQ || inst.Op == VCVTTPD2QQ || inst.Op == VCVTTPD2UQQ || inst.Op == VCVTPD2DQ || inst.Op == VCVTPD2UDQ || inst.Op == VCVTPD2QQ || inst.Op == VCVTPD2UQQ || inst.Op == VCVTPD2PS {
vexL := 0
isEvex := false
for i, p := range inst.Prefix {
if p.IsEVEX() && i+3 < len(inst.Prefix) && inst.Prefix[i+3] != 0 {
vexL = int((inst.Prefix[i+3]&0xFF)>>5) & 3
isEvex = true
break
} else if p.IsVEX() && i+2 < len(inst.Prefix) {
if p&0xFF == 0xC4 {
vexL = int((inst.Prefix[i+2]&0xFF)>>2) & 1
} else if p&0xFF == 0xC5 {
vexL = int((inst.Prefix[i+1]&0xFF)>>2) & 1
}
break
}
}
if !isEvex || inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTPD2DQ {
switch vexL {
case 0:
op += "X"
case 1:
if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
op += "Y"
}
case 2:
if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
op += "Z"
}
}
}
} else if inst.Op == VCVTTSD2SI || inst.Op == VCVTTSS2SI || inst.Op == VCVTSD2SI || inst.Op == VCVTSS2SI || inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS {
is64 := false
if (inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS) && inst.MemBytes == 8 {
is64 = true
} else {
for _, a := range inst.Args {
if r, ok := a.(Reg); ok && RAX <= r && r <= R15 {
is64 = true
break
}
}
}
if inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS {
if is64 {
op += "Q"
} else {
op += "L"
}
} else {
if is64 {
op += "Q"
}
}
} else if plan9Suffix[inst.Op] {
s := inst.DataSize
if inst.MemBytes != 0 {
s = inst.MemBytes * 8
@ -83,6 +137,29 @@ func GoSyntax(inst Inst, pc uint64, symname SymLookup) string {
}
}
if inst.Broadcast {
op += ".BCST"
}
if inst.SAE {
if hasRC(inst.Op) {
switch inst.Rounding {
case 0:
op += ".RN_SAE"
case 1:
op += ".RD_SAE"
case 2:
op += ".RU_SAE"
case 3:
op += ".RZ_SAE"
}
} else {
op += ".SAE"
}
}
if inst.Zeroing {
op += ".Z"
}
if inst.Op == CMP {
// Use reads-left-to-right ordering for comparisons.
// See issue 60920.
@ -349,6 +426,94 @@ var plan9Reg = [...]string{
X13: "X13",
X14: "X14",
X15: "X15",
X16: "X16",
X17: "X17",
X18: "X18",
X19: "X19",
X20: "X20",
X21: "X21",
X22: "X22",
X23: "X23",
X24: "X24",
X25: "X25",
X26: "X26",
X27: "X27",
X28: "X28",
X29: "X29",
X30: "X30",
X31: "X31",
Y0: "Y0",
Y1: "Y1",
Y2: "Y2",
Y3: "Y3",
Y4: "Y4",
Y5: "Y5",
Y6: "Y6",
Y7: "Y7",
Y8: "Y8",
Y9: "Y9",
Y10: "Y10",
Y11: "Y11",
Y12: "Y12",
Y13: "Y13",
Y14: "Y14",
Y15: "Y15",
Y16: "Y16",
Y17: "Y17",
Y18: "Y18",
Y19: "Y19",
Y20: "Y20",
Y21: "Y21",
Y22: "Y22",
Y23: "Y23",
Y24: "Y24",
Y25: "Y25",
Y26: "Y26",
Y27: "Y27",
Y28: "Y28",
Y29: "Y29",
Y30: "Y30",
Y31: "Y31",
Z0: "Z0",
Z1: "Z1",
Z2: "Z2",
Z3: "Z3",
Z4: "Z4",
Z5: "Z5",
Z6: "Z6",
Z7: "Z7",
Z8: "Z8",
Z9: "Z9",
Z10: "Z10",
Z11: "Z11",
Z12: "Z12",
Z13: "Z13",
Z14: "Z14",
Z15: "Z15",
Z16: "Z16",
Z17: "Z17",
Z18: "Z18",
Z19: "Z19",
Z20: "Z20",
Z21: "Z21",
Z22: "Z22",
Z23: "Z23",
Z24: "Z24",
Z25: "Z25",
Z26: "Z26",
Z27: "Z27",
Z28: "Z28",
Z29: "Z29",
Z30: "Z30",
Z31: "Z31",
K0: "K0",
K1: "K1",
K2: "K2",
K3: "K3",
K4: "K4",
K5: "K5",
K6: "K6",
K7: "K7",
CS: "CS",
SS: "SS",
DS: "DS",

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ github.com/google/pprof/third_party/svgpan
# github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b
## explicit; go 1.13
github.com/ianlancetaylor/demangle
# golang.org/x/arch v0.27.1-0.20260513003155-2ebc08890589
# golang.org/x/arch v0.27.1-0.20260521044007-9c1a596a2c97
## explicit; go 1.25.0
golang.org/x/arch/arm/armasm
golang.org/x/arch/arm64/arm64asm