whatcanGOwrong

This commit is contained in:
2024-09-19 21:38:24 -04:00
commit d0ae4d841d
17908 changed files with 4096831 additions and 0 deletions
@@ -0,0 +1,913 @@
// Copyright 2018 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 main
import (
"bytes"
"io/ioutil"
"path/filepath"
"regexp"
"strings"
"sync"
"testing"
"golang.org/x/arch/x86/xeddata"
)
func newTestContext(t testing.TB) *context {
ctx := &context{xedPath: filepath.Join("testdata", "xedpath")}
db, err := xeddata.NewDatabase(ctx.xedPath)
if err != nil {
t.Fatalf("open test database: %v", err)
}
ctx.db = db
return ctx
}
func newStringSet(keys ...string) map[string]bool {
set := make(map[string]bool)
for _, k := range keys {
set[k] = true
}
return set
}
func generateToString(t *testing.T) string {
ctx := newTestContext(t)
buildTables(ctx)
var buf bytes.Buffer
writeTables(&buf, ctx)
return buf.String()
}
func TestOutput(t *testing.T) {
// Ytab lists and optabs output checks.
//
// These tests are very fragile.
// Slight changes can invalidate them.
// It is better to keep testCases count at the minimum.
type testCase struct {
opcode string
ytabs string
optabLines string
}
var testCases []testCase
{
opcodeRE := regexp.MustCompile(`as: ([A-Z][A-Z0-9]*)`)
data, err := ioutil.ReadFile(filepath.Join("testdata", "golden.txt"))
if err != nil {
t.Fatalf("read golden file: %v", err)
}
for _, entry := range bytes.Split(data, []byte("======")) {
parts := bytes.Split(entry, []byte("----"))
ytabs := parts[0]
optabLines := parts[1]
opcode := opcodeRE.FindSubmatch(optabLines)[1]
testCases = append(testCases, testCase{
ytabs: strings.TrimSpace(string(ytabs)),
optabLines: strings.TrimSpace(string(optabLines)),
opcode: string(opcode)[len("A"):],
})
}
}
output := generateToString(t)
for _, tc := range testCases {
if !strings.Contains(output, tc.ytabs) {
t.Errorf("%s: ytabs not matched", tc.opcode)
}
if !strings.Contains(output, tc.optabLines) {
t.Errorf("%s: optab lines not matched", tc.opcode)
}
}
}
func TestOutputStability(t *testing.T) {
// Generate output count+1 times and check that every time
// it is exactly the same string.
//
// The output should be deterministic to avoid unwanted diffs
// between each code generation.
const count = 8
want := generateToString(t)
var wg sync.WaitGroup
for i := 0; i < count; i++ {
wg.Add(1)
go func(i int) {
if want != generateToString(t) {
t.Errorf("output #%d mismatches", i)
}
wg.Done()
}(i)
}
wg.Wait()
}
func TestOpcodeCoverage(t *testing.T) {
// Check that generator produces all expected opcodes from testdata files.
// All opcodes are in Go syntax.
// VEX/EVEX opcodes collected from XED-based x86.csv.
expectedOpcodes := newStringSet(
"ANDNL",
"ANDNQ",
"BEXTRL",
"BEXTRQ",
"BLSIL",
"BLSIQ",
"BLSMSKL",
"BLSMSKQ",
"BLSRL",
"BLSRQ",
"BZHIL",
"BZHIQ",
"KADDB",
"KADDD",
"KADDQ",
"KADDW",
"KANDB",
"KANDD",
"KANDNB",
"KANDND",
"KANDNQ",
"KANDNW",
"KANDQ",
"KANDW",
"KMOVB",
"KMOVD",
"KMOVQ",
"KMOVW",
"KNOTB",
"KNOTD",
"KNOTQ",
"KNOTW",
"KORB",
"KORD",
"KORQ",
"KORTESTB",
"KORTESTD",
"KORTESTQ",
"KORTESTW",
"KORW",
"KSHIFTLB",
"KSHIFTLD",
"KSHIFTLQ",
"KSHIFTLW",
"KSHIFTRB",
"KSHIFTRD",
"KSHIFTRQ",
"KSHIFTRW",
"KTESTB",
"KTESTD",
"KTESTQ",
"KTESTW",
"KUNPCKBW",
"KUNPCKDQ",
"KUNPCKWD",
"KXNORB",
"KXNORD",
"KXNORQ",
"KXNORW",
"KXORB",
"KXORD",
"KXORQ",
"KXORW",
"MULXL",
"MULXQ",
"PDEPL",
"PDEPQ",
"PEXTL",
"PEXTQ",
"RORXL",
"RORXQ",
"SARXL",
"SARXQ",
"SHLXL",
"SHLXQ",
"SHRXL",
"SHRXQ",
"V4FMADDPS",
"V4FMADDSS",
"V4FNMADDPS",
"V4FNMADDSS",
"VADDPD",
"VADDPS",
"VADDSD",
"VADDSS",
"VADDSUBPD",
"VADDSUBPS",
"VAESDEC",
"VAESDECLAST",
"VAESENC",
"VAESENCLAST",
"VAESIMC",
"VAESKEYGENASSIST",
"VALIGND",
"VALIGNQ",
"VANDNPD",
"VANDNPS",
"VANDPD",
"VANDPS",
"VBLENDMPD",
"VBLENDMPS",
"VBLENDPD",
"VBLENDPS",
"VBLENDVPD",
"VBLENDVPS",
"VBROADCASTF128",
"VBROADCASTF32X2",
"VBROADCASTF32X4",
"VBROADCASTF32X8",
"VBROADCASTF64X2",
"VBROADCASTF64X4",
"VBROADCASTI128",
"VBROADCASTI32X2",
"VBROADCASTI32X4",
"VBROADCASTI32X8",
"VBROADCASTI64X2",
"VBROADCASTI64X4",
"VBROADCASTSD",
"VBROADCASTSS",
"VCMPPD",
"VCMPPS",
"VCMPSD",
"VCMPSS",
"VCOMISD",
"VCOMISS",
"VCOMPRESSPD",
"VCOMPRESSPS",
"VCVTDQ2PD",
"VCVTDQ2PS",
"VCVTPD2DQ",
"VCVTPD2DQX",
"VCVTPD2DQY",
"VCVTPD2PS",
"VCVTPD2PSX",
"VCVTPD2PSY",
"VCVTPD2QQ",
"VCVTPD2UDQ",
"VCVTPD2UDQX",
"VCVTPD2UDQY",
"VCVTPD2UQQ",
"VCVTPH2PS",
"VCVTPS2DQ",
"VCVTPS2PD",
"VCVTPS2PH",
"VCVTPS2QQ",
"VCVTPS2UDQ",
"VCVTPS2UQQ",
"VCVTQQ2PD",
"VCVTQQ2PS",
"VCVTQQ2PSX",
"VCVTQQ2PSY",
"VCVTSD2SI",
"VCVTSD2SIQ",
"VCVTSD2SS",
"VCVTSD2USIL",
"VCVTSD2USIQ",
"VCVTSI2SDL",
"VCVTSI2SDQ",
"VCVTSI2SSL",
"VCVTSI2SSQ",
"VCVTSS2SD",
"VCVTSS2SI",
"VCVTSS2SIQ",
"VCVTSS2USIL",
"VCVTSS2USIQ",
"VCVTTPD2DQ",
"VCVTTPD2DQX",
"VCVTTPD2DQY",
"VCVTTPD2QQ",
"VCVTTPD2UDQ",
"VCVTTPD2UDQX",
"VCVTTPD2UDQY",
"VCVTTPD2UQQ",
"VCVTTPS2DQ",
"VCVTTPS2QQ",
"VCVTTPS2UDQ",
"VCVTTPS2UQQ",
"VCVTTSD2SI",
"VCVTTSD2SIQ",
"VCVTTSD2USIL",
"VCVTTSD2USIQ",
"VCVTTSS2SI",
"VCVTTSS2SIQ",
"VCVTTSS2USIL",
"VCVTTSS2USIQ",
"VCVTUDQ2PD",
"VCVTUDQ2PS",
"VCVTUQQ2PD",
"VCVTUQQ2PS",
"VCVTUQQ2PSX",
"VCVTUQQ2PSY",
"VCVTUSI2SDL",
"VCVTUSI2SDQ",
"VCVTUSI2SSL",
"VCVTUSI2SSQ",
"VDBPSADBW",
"VDIVPD",
"VDIVPS",
"VDIVSD",
"VDIVSS",
"VDPPD",
"VDPPS",
"VEXP2PD",
"VEXP2PS",
"VEXPANDPD",
"VEXPANDPS",
"VEXTRACTF128",
"VEXTRACTF32X4",
"VEXTRACTF32X8",
"VEXTRACTF64X2",
"VEXTRACTF64X4",
"VEXTRACTI128",
"VEXTRACTI32X4",
"VEXTRACTI32X8",
"VEXTRACTI64X2",
"VEXTRACTI64X4",
"VEXTRACTPS",
"VFIXUPIMMPD",
"VFIXUPIMMPS",
"VFIXUPIMMSD",
"VFIXUPIMMSS",
"VFMADD132PD",
"VFMADD132PS",
"VFMADD132SD",
"VFMADD132SS",
"VFMADD213PD",
"VFMADD213PS",
"VFMADD213SD",
"VFMADD213SS",
"VFMADD231PD",
"VFMADD231PS",
"VFMADD231SD",
"VFMADD231SS",
"VFMADDPD",
"VFMADDPS",
"VFMADDSD",
"VFMADDSS",
"VFMADDSUB132PD",
"VFMADDSUB132PS",
"VFMADDSUB213PD",
"VFMADDSUB213PS",
"VFMADDSUB231PD",
"VFMADDSUB231PS",
"VFMADDSUBPD",
"VFMADDSUBPS",
"VFMSUB132PD",
"VFMSUB132PS",
"VFMSUB132SD",
"VFMSUB132SS",
"VFMSUB213PD",
"VFMSUB213PS",
"VFMSUB213SD",
"VFMSUB213SS",
"VFMSUB231PD",
"VFMSUB231PS",
"VFMSUB231SD",
"VFMSUB231SS",
"VFMSUBADD132PD",
"VFMSUBADD132PS",
"VFMSUBADD213PD",
"VFMSUBADD213PS",
"VFMSUBADD231PD",
"VFMSUBADD231PS",
"VFMSUBADDPD",
"VFMSUBADDPS",
"VFMSUBPD",
"VFMSUBPS",
"VFMSUBSD",
"VFMSUBSS",
"VFNMADD132PD",
"VFNMADD132PS",
"VFNMADD132SD",
"VFNMADD132SS",
"VFNMADD213PD",
"VFNMADD213PS",
"VFNMADD213SD",
"VFNMADD213SS",
"VFNMADD231PD",
"VFNMADD231PS",
"VFNMADD231SD",
"VFNMADD231SS",
"VFNMADDPD",
"VFNMADDPS",
"VFNMADDSD",
"VFNMADDSS",
"VFNMSUB132PD",
"VFNMSUB132PS",
"VFNMSUB132SD",
"VFNMSUB132SS",
"VFNMSUB213PD",
"VFNMSUB213PS",
"VFNMSUB213SD",
"VFNMSUB213SS",
"VFNMSUB231PD",
"VFNMSUB231PS",
"VFNMSUB231SD",
"VFNMSUB231SS",
"VFNMSUBPD",
"VFNMSUBPS",
"VFNMSUBSD",
"VFNMSUBSS",
"VFPCLASSPDX",
"VFPCLASSPDY",
"VFPCLASSPDZ",
"VFPCLASSPSX",
"VFPCLASSPSY",
"VFPCLASSPSZ",
"VFPCLASSSD",
"VFPCLASSSS",
"VGATHERDPD",
"VGATHERDPS",
"VGATHERPF0DPD",
"VGATHERPF0DPS",
"VGATHERPF0QPD",
"VGATHERPF0QPS",
"VGATHERPF1DPD",
"VGATHERPF1DPS",
"VGATHERPF1QPD",
"VGATHERPF1QPS",
"VGATHERQPD",
"VGATHERQPS",
"VGETEXPPD",
"VGETEXPPS",
"VGETEXPSD",
"VGETEXPSS",
"VGETMANTPD",
"VGETMANTPS",
"VGETMANTSD",
"VGETMANTSS",
"VGF2P8AFFINEINVQB",
"VGF2P8AFFINEQB",
"VGF2P8MULB",
"VHADDPD",
"VHADDPS",
"VHSUBPD",
"VHSUBPS",
"VINSERTF128",
"VINSERTF32X4",
"VINSERTF32X8",
"VINSERTF64X2",
"VINSERTF64X4",
"VINSERTI128",
"VINSERTI32X4",
"VINSERTI32X8",
"VINSERTI64X2",
"VINSERTI64X4",
"VINSERTPS",
"VLDDQU",
"VLDMXCSR",
"VMASKMOVDQU",
"VMASKMOVPD",
"VMASKMOVPS",
"VMAXPD",
"VMAXPS",
"VMAXSD",
"VMAXSS",
"VMINPD",
"VMINPS",
"VMINSD",
"VMINSS",
"VMOVAPD",
"VMOVAPS",
"VMOVD",
"VMOVDDUP",
"VMOVDQA",
"VMOVDQA32",
"VMOVDQA64",
"VMOVDQU",
"VMOVDQU16",
"VMOVDQU32",
"VMOVDQU64",
"VMOVDQU8",
"VMOVHLPS",
"VMOVHPD",
"VMOVHPS",
"VMOVLHPS",
"VMOVLPD",
"VMOVLPS",
"VMOVMSKPD",
"VMOVMSKPS",
"VMOVNTDQ",
"VMOVNTDQA",
"VMOVNTPD",
"VMOVNTPS",
"VMOVQ",
"VMOVSD",
"VMOVSHDUP",
"VMOVSLDUP",
"VMOVSS",
"VMOVUPD",
"VMOVUPS",
"VMPSADBW",
"VMULPD",
"VMULPS",
"VMULSD",
"VMULSS",
"VORPD",
"VORPS",
"VP4DPWSSD",
"VP4DPWSSDS",
"VPABSB",
"VPABSD",
"VPABSQ",
"VPABSW",
"VPACKSSDW",
"VPACKSSWB",
"VPACKUSDW",
"VPACKUSWB",
"VPADDB",
"VPADDD",
"VPADDQ",
"VPADDSB",
"VPADDSW",
"VPADDUSB",
"VPADDUSW",
"VPADDW",
"VPALIGNR",
"VPAND",
"VPANDD",
"VPANDN",
"VPANDND",
"VPANDNQ",
"VPANDQ",
"VPAVGB",
"VPAVGW",
"VPBLENDD",
"VPBLENDMB",
"VPBLENDMD",
"VPBLENDMQ",
"VPBLENDMW",
"VPBLENDVB",
"VPBLENDW",
"VPBROADCASTB",
"VPBROADCASTD",
"VPBROADCASTMB2Q",
"VPBROADCASTMW2D",
"VPBROADCASTQ",
"VPBROADCASTW",
"VPCLMULQDQ",
"VPCMPB",
"VPCMPD",
"VPCMPEQB",
"VPCMPEQD",
"VPCMPEQQ",
"VPCMPEQW",
"VPCMPESTRI",
"VPCMPESTRM",
"VPCMPGTB",
"VPCMPGTD",
"VPCMPGTQ",
"VPCMPGTW",
"VPCMPISTRI",
"VPCMPISTRM",
"VPCMPQ",
"VPCMPUB",
"VPCMPUD",
"VPCMPUQ",
"VPCMPUW",
"VPCMPW",
"VPCOMPRESSB",
"VPCOMPRESSD",
"VPCOMPRESSQ",
"VPCOMPRESSW",
"VPCONFLICTD",
"VPCONFLICTQ",
"VPDPBUSD",
"VPDPBUSDS",
"VPDPWSSD",
"VPDPWSSDS",
"VPERM2F128",
"VPERM2I128",
"VPERMB",
"VPERMD",
"VPERMI2B",
"VPERMI2D",
"VPERMI2PD",
"VPERMI2PS",
"VPERMI2Q",
"VPERMI2W",
"VPERMIL2PD",
"VPERMIL2PS",
"VPERMILPD",
"VPERMILPS",
"VPERMPD",
"VPERMPS",
"VPERMQ",
"VPERMT2B",
"VPERMT2D",
"VPERMT2PD",
"VPERMT2PS",
"VPERMT2Q",
"VPERMT2W",
"VPERMW",
"VPEXPANDB",
"VPEXPANDD",
"VPEXPANDQ",
"VPEXPANDW",
"VPEXTRB",
"VPEXTRD",
"VPEXTRQ",
"VPEXTRW",
"VPGATHERDD",
"VPGATHERDQ",
"VPGATHERQD",
"VPGATHERQQ",
"VPHADDD",
"VPHADDSW",
"VPHADDW",
"VPHMINPOSUW",
"VPHSUBD",
"VPHSUBSW",
"VPHSUBW",
"VPINSRB",
"VPINSRD",
"VPINSRQ",
"VPINSRW",
"VPLZCNTD",
"VPLZCNTQ",
"VPMADD52HUQ",
"VPMADD52LUQ",
"VPMADDUBSW",
"VPMADDWD",
"VPMASKMOVD",
"VPMASKMOVQ",
"VPMAXSB",
"VPMAXSD",
"VPMAXSQ",
"VPMAXSW",
"VPMAXUB",
"VPMAXUD",
"VPMAXUQ",
"VPMAXUW",
"VPMINSB",
"VPMINSD",
"VPMINSQ",
"VPMINSW",
"VPMINUB",
"VPMINUD",
"VPMINUQ",
"VPMINUW",
"VPMOVB2M",
"VPMOVD2M",
"VPMOVDB",
"VPMOVDW",
"VPMOVM2B",
"VPMOVM2D",
"VPMOVM2Q",
"VPMOVM2W",
"VPMOVMSKB",
"VPMOVQ2M",
"VPMOVQB",
"VPMOVQD",
"VPMOVQW",
"VPMOVSDB",
"VPMOVSDW",
"VPMOVSQB",
"VPMOVSQD",
"VPMOVSQW",
"VPMOVSWB",
"VPMOVSXBD",
"VPMOVSXBQ",
"VPMOVSXBW",
"VPMOVSXDQ",
"VPMOVSXWD",
"VPMOVSXWQ",
"VPMOVUSDB",
"VPMOVUSDW",
"VPMOVUSQB",
"VPMOVUSQD",
"VPMOVUSQW",
"VPMOVUSWB",
"VPMOVW2M",
"VPMOVWB",
"VPMOVZXBD",
"VPMOVZXBQ",
"VPMOVZXBW",
"VPMOVZXDQ",
"VPMOVZXWD",
"VPMOVZXWQ",
"VPMULDQ",
"VPMULHRSW",
"VPMULHUW",
"VPMULHW",
"VPMULLD",
"VPMULLQ",
"VPMULLW",
"VPMULTISHIFTQB",
"VPMULUDQ",
"VPOPCNTB",
"VPOPCNTD",
"VPOPCNTQ",
"VPOPCNTW",
"VPOR",
"VPORD",
"VPORQ",
"VPROLD",
"VPROLQ",
"VPROLVD",
"VPROLVQ",
"VPRORD",
"VPRORQ",
"VPRORVD",
"VPRORVQ",
"VPSADBW",
"VPSCATTERDD",
"VPSCATTERDQ",
"VPSCATTERQD",
"VPSCATTERQQ",
"VPSHLDD",
"VPSHLDQ",
"VPSHLDVD",
"VPSHLDVQ",
"VPSHLDVW",
"VPSHLDW",
"VPSHRDD",
"VPSHRDQ",
"VPSHRDVD",
"VPSHRDVQ",
"VPSHRDVW",
"VPSHRDW",
"VPSHUFB",
"VPSHUFBITQMB",
"VPSHUFD",
"VPSHUFHW",
"VPSHUFLW",
"VPSIGNB",
"VPSIGND",
"VPSIGNW",
"VPSLLD",
"VPSLLDQ",
"VPSLLQ",
"VPSLLVD",
"VPSLLVQ",
"VPSLLVW",
"VPSLLW",
"VPSRAD",
"VPSRAQ",
"VPSRAVD",
"VPSRAVQ",
"VPSRAVW",
"VPSRAW",
"VPSRLD",
"VPSRLDQ",
"VPSRLQ",
"VPSRLVD",
"VPSRLVQ",
"VPSRLVW",
"VPSRLW",
"VPSUBB",
"VPSUBD",
"VPSUBQ",
"VPSUBSB",
"VPSUBSW",
"VPSUBUSB",
"VPSUBUSW",
"VPSUBW",
"VPTERNLOGD",
"VPTERNLOGQ",
"VPTEST",
"VPTESTMB",
"VPTESTMD",
"VPTESTMQ",
"VPTESTMW",
"VPTESTNMB",
"VPTESTNMD",
"VPTESTNMQ",
"VPTESTNMW",
"VPUNPCKHBW",
"VPUNPCKHDQ",
"VPUNPCKHQDQ",
"VPUNPCKHWD",
"VPUNPCKLBW",
"VPUNPCKLDQ",
"VPUNPCKLQDQ",
"VPUNPCKLWD",
"VPXOR",
"VPXORD",
"VPXORQ",
"VRANGEPD",
"VRANGEPS",
"VRANGESD",
"VRANGESS",
"VRCP14PD",
"VRCP14PS",
"VRCP14SD",
"VRCP14SS",
"VRCP28PD",
"VRCP28PS",
"VRCP28SD",
"VRCP28SS",
"VRCPPS",
"VRCPSS",
"VREDUCEPD",
"VREDUCEPS",
"VREDUCESD",
"VREDUCESS",
"VRNDSCALEPD",
"VRNDSCALEPS",
"VRNDSCALESD",
"VRNDSCALESS",
"VROUNDPD",
"VROUNDPS",
"VROUNDSD",
"VROUNDSS",
"VRSQRT14PD",
"VRSQRT14PS",
"VRSQRT14SD",
"VRSQRT14SS",
"VRSQRT28PD",
"VRSQRT28PS",
"VRSQRT28SD",
"VRSQRT28SS",
"VRSQRTPS",
"VRSQRTSS",
"VSCALEFPD",
"VSCALEFPS",
"VSCALEFSD",
"VSCALEFSS",
"VSCATTERDPD",
"VSCATTERDPS",
"VSCATTERPF0DPD",
"VSCATTERPF0DPS",
"VSCATTERPF0QPD",
"VSCATTERPF0QPS",
"VSCATTERPF1DPD",
"VSCATTERPF1DPS",
"VSCATTERPF1QPD",
"VSCATTERPF1QPS",
"VSCATTERQPD",
"VSCATTERQPS",
"VSHUFF32X4",
"VSHUFF64X2",
"VSHUFI32X4",
"VSHUFI64X2",
"VSHUFPD",
"VSHUFPS",
"VSQRTPD",
"VSQRTPS",
"VSQRTSD",
"VSQRTSS",
"VSTMXCSR",
"VSUBPD",
"VSUBPS",
"VSUBSD",
"VSUBSS",
"VTESTPD",
"VTESTPS",
"VUCOMISD",
"VUCOMISS",
"VUNPCKHPD",
"VUNPCKHPS",
"VUNPCKLPD",
"VUNPCKLPS",
"VXORPD",
"VXORPS",
"VZEROALL",
"VZEROUPPER")
// AMD-specific VEX opcodes.
// Excluded from x86avxgen output for now.
amdOpcodes := newStringSet(
"VFMADDPD",
"VFMADDPS",
"VFMADDSD",
"VFMADDSS",
"VFMADDSUBPD",
"VFMADDSUBPS",
"VFMSUBADDPD",
"VFMSUBADDPS",
"VFMSUBPD",
"VFMSUBPS",
"VFMSUBSD",
"VFMSUBSS",
"VFNMADDPD",
"VFNMADDPS",
"VFNMADDSD",
"VFNMADDSS",
"VFNMSUBPD",
"VFNMSUBPS",
"VFNMSUBSD",
"VFNMSUBSS",
"VPERMIL2PD",
"VPERMIL2PS")
ctx := newTestContext(t)
buildTables(ctx)
for op := range amdOpcodes {
delete(expectedOpcodes, op)
}
for op := range ctx.optabs {
delete(expectedOpcodes, op)
}
for op := range expectedOpcodes {
t.Errorf("missing opcode: %s", op)
}
}
@@ -0,0 +1,395 @@
// Copyright 2018 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 main
import (
"fmt"
"log"
"regexp"
"strings"
"golang.org/x/arch/x86/xeddata"
)
// encoding is decoded XED instruction pattern.
type encoding struct {
// opbyte is opcode byte (one that follows [E]VEX prefix).
// It's called "opcode" in Intel manual, but we use that for
// instruction name (iclass in XED terms).
opbyte string
// opdigit is ModRM.Reg field used to encode opcode extension.
// In Intel manual, "/digit" notation is used.
opdigit string
// vex represents [E]VEX fields that are used in a first [E]VEX
// opBytes element (see prefixExpr function).
vex struct {
P string // 66/F2/F3
L string // 128/256/512
M string // 0F/0F38/0F3A
W string // W0/W1
}
// evexScale is a scaling factor used to calculate compact disp-8.
evexScale string
// evexBcstScale is like evexScale, but used during broadcasting.
// Empty for optab entries that do not have broadcasting support.
evexBcstScale string
// evex describes which features of EVEX can be used by optab entry.
// All flags are "false" for VEX-encoded insts.
evex struct {
// There is no "broadcast" flag because it's inferred
// from non-empty evexBcstScale.
SAE bool // EVEX.b controls SAE for reg-reg insts
Rounding bool // EVEX.b + EVEX.RC (VL) control rounding for FP insts
Zeroing bool // Instruction can use zeroing.
}
}
type decoder struct {
ctx *context
insts []*instruction
}
// decodeGroups fills ctx.groups with decoded instruction groups.
//
// Reads XED objects from ctx.xedPath.
func decodeGroups(ctx *context) {
d := decoder{ctx: ctx}
groups := make(map[string][]*instruction)
for _, inst := range d.DecodeAll() {
groups[inst.opcode] = append(groups[inst.opcode], inst)
}
for op, insts := range groups {
ctx.groups = append(ctx.groups, &instGroup{
opcode: op,
list: insts,
})
}
}
// DecodeAll decodes every XED instruction.
func (d *decoder) DecodeAll() []*instruction {
err := xeddata.WalkInsts(d.ctx.xedPath, func(inst *xeddata.Inst) {
inst.Pattern = xeddata.ExpandStates(d.ctx.db, inst.Pattern)
pset := xeddata.NewPatternSet(inst.Pattern)
opcode := inst.Iclass
switch {
case inst.HasAttribute("AMDONLY") || inst.Extension == "XOP":
return // Only VEX and EVEX are supported
case !pset.Is("VEX") && !pset.Is("EVEX"):
return // Skip non-AVX instructions
case inst.RealOpcode == "N":
return // Skip unstable instructions
}
// Expand some patterns to simplify decodePattern.
pset.Replace("FIX_ROUND_LEN128()", "VL=0")
pset.Replace("FIX_ROUND_LEN512()", "VL=2")
mask, args := d.decodeArgs(pset, inst)
d.insts = append(d.insts, &instruction{
pset: pset,
opcode: opcode,
mask: mask,
args: args,
enc: d.decodePattern(pset, inst),
})
})
if err != nil {
log.Fatalf("walk insts: %v", err)
}
return d.insts
}
// registerArgs maps XED argument name RHS to its decoded version.
var registerArgs = map[string]argument{
"GPR32_R()": {"Yrl", "reg"},
"GPR64_R()": {"Yrl", "reg"},
"VGPR32_R()": {"Yrl", "reg"},
"VGPR64_R()": {"Yrl", "reg"},
"VGPR32_N()": {"Yrl", "regV"},
"VGPR64_N()": {"Yrl", "regV"},
"GPR32_B()": {"Yrl", "reg/mem"},
"GPR64_B()": {"Yrl", "reg/mem"},
"VGPR32_B()": {"Yrl", "reg/mem"},
"VGPR64_B()": {"Yrl", "reg/mem"},
"XMM_R()": {"Yxr", "reg"},
"XMM_R3()": {"YxrEvex", "reg"},
"XMM_N()": {"Yxr", "regV"},
"XMM_N3()": {"YxrEvex", "regV"},
"XMM_B()": {"Yxr", "reg/mem"},
"XMM_B3()": {"YxrEvex", "reg/mem"},
"XMM_SE()": {"Yxr", "regIH"},
"YMM_R()": {"Yyr", "reg"},
"YMM_R3()": {"YyrEvex", "reg"},
"YMM_N()": {"Yyr", "regV"},
"YMM_N3()": {"YyrEvex", "regV"},
"YMM_B()": {"Yyr", "reg/mem"},
"YMM_B3()": {"YyrEvex", "reg/mem"},
"YMM_SE()": {"Yyr", "regIH"},
"ZMM_R3()": {"Yzr", "reg"},
"ZMM_N3()": {"Yzr", "regV"},
"ZMM_B3()": {"Yzr", "reg/mem"},
"MASK_R()": {"Yk", "reg"},
"MASK_N()": {"Yk", "regV"},
"MASK_B()": {"Yk", "reg/mem"},
"MASKNOT0()": {"Yknot0", "kmask"},
// Handled specifically in "generate".
"MASK1()": {"MASK1()", "MASK1()"},
}
func (d *decoder) decodeArgs(pset xeddata.PatternSet, inst *xeddata.Inst) (mask *argument, args []*argument) {
for i, f := range strings.Fields(inst.Operands) {
xarg, err := xeddata.NewOperand(d.ctx.db, f)
if err != nil {
log.Fatalf("%s: args[%d]: %v", inst, i, err)
}
switch {
case xarg.Action == "":
continue // Skip meta args like EMX_BROADCAST_1TO32_8
case !xarg.IsVisible():
continue
}
arg := &argument{}
args = append(args, arg)
switch xarg.NameLHS() {
case "IMM0":
if xarg.Width != "b" {
log.Fatalf("%s: args[%d]: expected width=b, found %s", inst, i, xarg.Width)
}
if pset["IMM0SIGNED=1"] {
arg.ytype = "Yi8"
} else {
arg.ytype = "Yu8"
}
arg.zkind = "imm8"
case "REG0", "REG1", "REG2", "REG3":
rhs := xarg.NameRHS()
if rhs == "MASK1()" {
mask = arg
}
*arg = registerArgs[rhs]
if arg.ytype == "" {
log.Fatalf("%s: args[%d]: unexpected %s reg", inst, i, rhs)
}
if xarg.Attributes["MULTISOURCE4"] {
arg.ytype += "Multi4"
}
case "MEM0":
arg.ytype = pset.MatchOrDefault("Ym",
"VMODRM_XMM()", "Yxvm",
"VMODRM_YMM()", "Yyvm",
"UISA_VMODRM_XMM()", "YxvmEvex",
"UISA_VMODRM_YMM()", "YyvmEvex",
"UISA_VMODRM_ZMM()", "Yzvm",
)
arg.zkind = "reg/mem"
default:
log.Fatalf("%s: args[%d]: unexpected %s", inst, i, xarg.NameRHS())
}
}
// Reverse args.
for i := len(args)/2 - 1; i >= 0; i-- {
j := len(args) - 1 - i
args[i], args[j] = args[j], args[i]
}
return mask, args
}
func (d *decoder) decodePattern(pset xeddata.PatternSet, inst *xeddata.Inst) *encoding {
var enc encoding
enc.opdigit = d.findOpdigit(pset)
enc.opbyte = d.findOpbyte(pset, inst)
if strings.Contains(inst.Attributes, "DISP8_") {
enc.evexScale = d.findEVEXScale(pset)
enc.evexBcstScale = d.findEVEXBcstScale(pset, inst)
}
enc.vex.P = pset.Match(
"VEX_PREFIX=1", "66",
"VEX_PREFIX=2", "F2",
"VEX_PREFIX=3", "F3")
enc.vex.M = pset.Match(
"MAP=1", "0F",
"MAP=2", "0F38",
"MAP=3", "0F3A")
enc.vex.L = pset.MatchOrDefault("128",
"VL=0", "128",
"VL=1", "256",
"VL=2", "512")
enc.vex.W = pset.MatchOrDefault("W0",
"REXW=0", "W0",
"REXW=1", "W1")
if pset.Is("EVEX") {
enc.evex.SAE = strings.Contains(inst.Operands, "TXT=SAESTR")
enc.evex.Rounding = strings.Contains(inst.Operands, "TXT=ROUNDC")
enc.evex.Zeroing = strings.Contains(inst.Operands, "TXT=ZEROSTR")
}
// Prefix each non-empty part with vex or evex.
parts := [...]*string{
&enc.evexScale, &enc.evexBcstScale,
&enc.vex.P, &enc.vex.M, &enc.vex.L, &enc.vex.W,
}
for _, p := range parts {
if *p == "" {
continue
}
if pset.Is("EVEX") {
*p = "evex" + *p
} else {
*p = "vex" + *p
}
}
return &enc
}
func (d *decoder) findOpdigit(pset xeddata.PatternSet) string {
reg := pset.Index(
"REG[0b000]",
"REG[0b001]",
"REG[0b010]",
"REG[0b011]",
"REG[0b100]",
"REG[0b101]",
"REG[0b110]",
"REG[0b111]",
)
// Fixed ModRM.Reg field means that it is used for opcode extension.
if reg != -1 {
return fmt.Sprintf("0%d", reg)
}
return ""
}
// opbyteRE matches uint8 hex literal.
var opbyteRE = regexp.MustCompile(`0x[0-9A-F]{2}`)
func (d *decoder) findOpbyte(pset xeddata.PatternSet, inst *xeddata.Inst) string {
opbyte := ""
for k := range pset {
if opbyteRE.MatchString(k) {
if opbyte == "" {
opbyte = k
} else {
log.Fatalf("%s: multiple opbytes", inst)
}
}
}
return opbyte
}
func (d *decoder) findEVEXScale(pset xeddata.PatternSet) string {
switch {
case pset["NELEM_FULL()"], pset["NELEM_FULLMEM()"]:
return pset.Match(
"VL=0", "N16",
"VL=1", "N32",
"VL=2", "N64")
case pset["NELEM_MOVDDUP()"]:
return pset.Match(
"VL=0", "N8",
"VL=1", "N32",
"VL=2", "N64")
case pset["NELEM_HALF()"], pset["NELEM_HALFMEM()"]:
return pset.Match(
"VL=0", "N8",
"VL=1", "N16",
"VL=2", "N32")
case pset["NELEM_QUARTERMEM()"]:
return pset.Match(
"VL=0", "N4",
"VL=1", "N8",
"VL=2", "N16")
case pset["NELEM_EIGHTHMEM()"]:
return pset.Match(
"VL=0", "N2",
"VL=1", "N4",
"VL=2", "N8")
case pset["NELEM_TUPLE2()"]:
return pset.Match(
"ESIZE_32_BITS()", "N8",
"ESIZE_64_BITS()", "N16")
case pset["NELEM_TUPLE4()"]:
return pset.Match(
"ESIZE_32_BITS()", "N16",
"ESIZE_64_BITS()", "N32")
case pset["NELEM_TUPLE8()"]:
return "N32"
case pset["NELEM_MEM128()"], pset["NELEM_TUPLE1_4X()"]:
return "N16"
}
// Explicit list is required to make it possible to
// detect unhandled nonterminals for the caller.
scalars := [...]string{
"NELEM_SCALAR()",
"NELEM_GSCAT()",
"NELEM_GPR_READER()",
"NELEM_GPR_READER_BYTE()",
"NELEM_GPR_READER_WORD()",
"NELEM_GPR_WRITER_STORE()",
"NELEM_GPR_WRITER_STORE_BYTE()",
"NELEM_GPR_WRITER_STORE_WORD()",
"NELEM_GPR_WRITER_LDOP_D()",
"NELEM_GPR_WRITER_LDOP_Q()",
"NELEM_TUPLE1()",
"NELEM_TUPLE1_BYTE()",
"NELEM_TUPLE1_WORD()",
}
for _, scalar := range scalars {
if pset[scalar] {
return pset.Match(
"ESIZE_8_BITS()", "N1",
"ESIZE_16_BITS()", "N2",
"ESIZE_32_BITS()", "N4",
"ESIZE_64_BITS()", "N8")
}
}
return ""
}
func (d *decoder) findEVEXBcstScale(pset xeddata.PatternSet, inst *xeddata.Inst) string {
// Only FULL and HALF tuples are affected by the broadcasting.
switch {
case pset["NELEM_FULL()"]:
return pset.Match(
"ESIZE_32_BITS()", "BcstN4",
"ESIZE_64_BITS()", "BcstN8")
case pset["NELEM_HALF()"]:
return "BcstN4"
default:
if inst.HasAttribute("BROADCAST_ENABLED") {
log.Fatalf("%s: unexpected tuple for bcst", inst)
}
return ""
}
}
@@ -0,0 +1,255 @@
// Copyright 2018 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 main
import (
"bytes"
"log"
"strings"
)
// ytab is ytabList element.
type ytab struct {
Zcase string
Zoffset int
ArgList string // Ytypes that are matched by this ytab.
}
// ytabList is a named set of ytab objects.
// In asm6.go represented as []ytab.
type ytabList struct {
Name string
Ytabs []ytab
}
// optab describes instruction encodings for specific opcode.
type optab struct {
Opcode string
YtabList *ytabList
OpLines []string
}
type generator struct {
ctx *context
ytabLists map[string]*ytabList
}
// generateOptabs fills ctx.optabs and ctx.ytabLists with objects created
// from decoded instructions.
func generateOptabs(ctx *context) {
gen := generator{ctx: ctx, ytabLists: make(map[string]*ytabList)}
optabs := make(map[string]*optab)
for _, g := range ctx.groups {
optabs[g.opcode] = gen.GenerateGroup(g)
}
ctx.optabs = optabs
ctx.ytabLists = gen.ytabLists
}
// GenerateGroup converts g into optab.
// Populates internal ytab list map.
func (gen *generator) GenerateGroup(g *instGroup) *optab {
var opLines []string
for _, inst := range g.list {
opLines = append(opLines, gen.generateOpLine(inst))
}
return &optab{
Opcode: "A" + g.opcode,
OpLines: opLines,
YtabList: gen.internYtabList(g),
}
}
// generateOpLine returns string that describes opBytes for single instruction form.
func (gen *generator) generateOpLine(inst *instruction) string {
parts := []string{gen.prefixExpr(inst)}
if inst.pset.Is("EVEX") {
parts = append(parts, gen.evexPrefixExpr(inst))
}
parts = append(parts, inst.enc.opbyte)
if inst.enc.opdigit != "" {
parts = append(parts, inst.enc.opdigit)
}
return strings.Join(parts, ", ")
}
func (gen *generator) prefixExpr(inst *instruction) string {
enc := inst.enc
return gen.joinPrefixParts([]string{
// Special constant that makes AVX byte different from 0x0F,
// making it unnecessary to check for both VEX+EVEX when
// assigning dealing with legacy instructions that skip it
// without advancing "z" counter.
"avxEscape",
enc.vex.L,
enc.vex.P,
enc.vex.M,
enc.vex.W,
})
}
func (gen *generator) evexPrefixExpr(inst *instruction) string {
enc := inst.enc
parts := []string{
enc.evexScale,
enc.evexBcstScale,
}
if enc.evex.SAE {
parts = append(parts, "evexSaeEnabled")
}
if enc.evex.Rounding {
parts = append(parts, "evexRoundingEnabled")
}
if enc.evex.Zeroing {
parts = append(parts, "evexZeroingEnabled")
}
return gen.joinPrefixParts(parts)
}
// joinPrefixParts returns the Go OR-expression for every non-empty name.
// If every name is empty, returns "0".
func (gen *generator) joinPrefixParts(names []string) string {
filterEmptyStrings := func(xs []string) []string {
ys := xs[:0]
for _, x := range xs {
if x != "" {
ys = append(ys, x)
}
}
return ys
}
names = filterEmptyStrings(names)
if len(names) == 0 {
return "0"
}
return strings.Join(names, "|")
}
// internYtabList returns ytabList for given group.
//
// Returned ytab lists are interned.
// Same ytab list can be returned for different groups.
func (gen *generator) internYtabList(g *instGroup) *ytabList {
var key string
{
var buf bytes.Buffer
for _, inst := range g.list {
buf.WriteString(inst.zform)
buf.WriteByte('=')
buf.WriteString(inst.YtypeListString())
buf.WriteByte(';')
}
key = buf.String()
}
if ylist := gen.ytabLists[key]; ylist != nil {
return ylist
}
var ytabs []ytab
for _, inst := range g.list {
zoffset := 2
if inst.pset.Is("EVEX") {
zoffset++ // Always at least 3 bytes
}
if inst.enc.opdigit != "" {
zoffset++
}
if inst.mask != nil {
ytabs = append(ytabs, gen.makeMaskYtabs(zoffset, inst)...)
} else {
ytabs = append(ytabs, gen.makeYtab(zoffset, inst.zform, inst.args))
}
}
ylist := &ytabList{
Name: "_y" + strings.ToLower(g.opcode),
Ytabs: ytabs,
}
gen.ytabLists[key] = ylist
return ylist
}
var zcaseByZform = map[string]string{
"evex imm8 reg kmask reg/mem": "Zevex_i_r_k_rm",
"evex imm8 reg reg/mem": "Zevex_i_r_rm",
"evex imm8 reg/mem kmask reg": "Zevex_i_rm_k_r",
"evex imm8 reg/mem kmask regV opdigit": "Zevex_i_rm_k_vo",
"evex imm8 reg/mem reg": "Zevex_i_rm_r",
"evex imm8 reg/mem regV opdigit": "Zevex_i_rm_vo",
"evex imm8 reg/mem regV kmask reg": "Zevex_i_rm_v_k_r",
"evex imm8 reg/mem regV reg": "Zevex_i_rm_v_r",
"evex kmask reg/mem opdigit": "Zevex_k_rmo",
"evex reg kmask reg/mem": "Zevex_r_k_rm",
"evex reg reg/mem": "Zevex_r_v_rm",
"evex reg regV kmask reg/mem": "Zevex_r_v_k_rm",
"evex reg regV reg/mem": "Zevex_r_v_rm",
"evex reg/mem kmask reg": "Zevex_rm_k_r",
"evex reg/mem reg": "Zevex_rm_v_r",
"evex reg/mem regV kmask reg": "Zevex_rm_v_k_r",
"evex reg/mem regV reg": "Zevex_rm_v_r",
"": "Zvex",
"imm8 reg reg/mem": "Zvex_i_r_rm",
"imm8 reg/mem reg": "Zvex_i_rm_r",
"imm8 reg/mem regV opdigit": "Zvex_i_rm_vo",
"imm8 reg/mem regV reg": "Zvex_i_rm_v_r",
"reg reg/mem": "Zvex_r_v_rm",
"reg regV reg/mem": "Zvex_r_v_rm",
"reg/mem opdigit": "Zvex_rm_v_ro",
"reg/mem reg": "Zvex_rm_v_r",
"reg/mem regV opdigit": "Zvex_rm_r_vo",
"reg/mem regV reg": "Zvex_rm_v_r",
"reg/mem": "Zvex_rm_v_r",
"regIH reg/mem regV reg": "Zvex_hr_rm_v_r",
"regV reg/mem reg": "Zvex_v_rm_r",
}
func (gen *generator) makeYtab(zoffset int, zform string, args []*argument) ytab {
var ytypes []string
for _, arg := range args {
if arg.ytype != "Ynone" {
ytypes = append(ytypes, arg.ytype)
}
}
argList := strings.Join(ytypes, ", ")
zcase := zcaseByZform[zform]
if zcase == "" {
log.Fatalf("no zcase for %q", zform)
}
return ytab{
Zcase: zcase,
Zoffset: zoffset,
ArgList: argList,
}
}
// makeMaskYtabs returns 2 ytabs created from instruction with MASK1() argument.
//
// This is required due to how masking is implemented in asm6.
// Single MASK1() instruction produces 2 ytabs, for example:
// 1. OP xmm, mem | Yxr, Yxm | Does not permit K arguments (K0 implied)
// 2. OP xmm, K2, mem | Yxr, Yknot0, Yxm | Does not permit K0 argument
//
// This function also exploits that both ytab entries have same opbytes,
// hence it is efficient to emit only one opbytes line and 0 Z-offset
// for first ytab object.
func (gen *generator) makeMaskYtabs(zoffset int, inst *instruction) []ytab {
var k0 ytab
{
zform := strings.Replace(inst.zform, "MASK1() ", "", 1)
inst.mask.ytype = "Ynone"
k0 = gen.makeYtab(0, zform, inst.args)
}
var knot0 ytab
{
zform := strings.Replace(inst.zform, "MASK1() ", "kmask ", 1)
inst.mask.ytype = "Yknot0"
knot0 = gen.makeYtab(zoffset, zform, inst.args)
}
inst.mask.ytype = "MASK1()" // Restore Y-type
return []ytab{k0, knot0}
}
@@ -0,0 +1,64 @@
// Copyright 2018 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 main
import (
"strings"
"golang.org/x/arch/x86/xeddata"
)
// argument is a describes single instruction operand properties.
type argument struct {
// ytype is argument class as returned by asm6 "oclass" function.
ytype string
// zkind is a partial Z-case matcher.
// Determines which Z-case handles the encoding of instruction.
zkind string
}
// instruction is decoded XED instruction.
// Used to produce ytabs and optabs in later phases.
type instruction struct {
// opcode is instruction symbolic name.
opcode string
pset xeddata.PatternSet
enc *encoding
// mask is EVEX K-register argument; points to args element.
// Used to emit Yk0+Yknot0 table entries.
// Nil for VEX-encoded insts.
mask *argument
args []*argument
// zform is a pattern that determines which encoder Z-case is used.
// We store zform instead of zcase directly because it's further
// expanded during optabs generation.
zform string
}
// String returns short inst printed representation.
func (inst *instruction) String() string { return inst.opcode }
// YtypeListString joins each argument Y-type and returns the result.
func (inst *instruction) YtypeListString() string {
var parts []string
for _, arg := range inst.args {
parts = append(parts, arg.ytype)
}
return strings.Join(parts, " ")
}
// ArgIndexByZkind returns first argument matching given zkind or -1.
func (inst *instruction) ArgIndexByZkind(zkind string) int {
for i, arg := range inst.args {
if arg.zkind == zkind {
return i
}
}
return -1
}
@@ -0,0 +1,361 @@
// Copyright 2018 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 main
import (
"flag"
"fmt"
"log"
"os"
"sort"
"strings"
"golang.org/x/arch/x86/xeddata"
)
// instGroup holds a list of instructions with same opcode.
type instGroup struct {
opcode string
list []*instruction
}
// context is x86avxgen program execution state.
type context struct {
db *xeddata.Database
groups []*instGroup
optabs map[string]*optab
ytabLists map[string]*ytabList
// Command line arguments:
xedPath string
}
func main() {
log.SetPrefix("x86avxgen: ")
log.SetFlags(log.Lshortfile)
var ctx context
runSteps(&ctx,
parseFlags,
openDatabase,
buildTables,
printTables)
}
func buildTables(ctx *context) {
// Order of steps is significant.
runSteps(ctx,
decodeGroups,
mergeRegMem,
addGoSuffixes,
mergeWIG,
assignZforms,
sortGroups,
generateOptabs)
}
func runSteps(ctx *context, steps ...func(*context)) {
for _, f := range steps {
f(ctx)
}
}
func parseFlags(ctx *context) {
flag.StringVar(&ctx.xedPath, "xedPath", "./xedpath",
"XED datafiles location")
flag.Parse()
}
func openDatabase(ctx *context) {
db, err := xeddata.NewDatabase(ctx.xedPath)
if err != nil {
log.Fatalf("open database: %v", err)
}
ctx.db = db
}
// mergeRegMem merges reg-only with mem-only instructions.
// For example: {MOVQ reg, mem} + {MOVQ reg, reg} = {MOVQ reg, reg/mem}.
func mergeRegMem(ctx *context) {
mergeKey := func(inst *instruction) string {
return strings.Join([]string{
fmt.Sprint(len(inst.args)),
inst.enc.opbyte,
inst.enc.opdigit,
inst.enc.vex.P,
inst.enc.vex.L,
inst.enc.vex.M,
inst.enc.vex.W,
}, " ")
}
for _, g := range ctx.groups {
regOnly := make(map[string]*instruction)
memOnly := make(map[string]*instruction)
list := g.list[:0]
for _, inst := range g.list {
switch {
case inst.pset.Is("RegOnly"):
regOnly[mergeKey(inst)] = inst
case inst.pset.Is("MemOnly"):
memOnly[mergeKey(inst)] = inst
default:
if len(inst.args) == 0 {
list = append(list, inst)
continue
}
log.Fatalf("%s: unexpected MOD value", inst)
}
}
for k, m := range memOnly {
r := regOnly[k]
if r != nil {
index := m.ArgIndexByZkind("reg/mem")
arg := m.args[index]
switch ytype := r.args[index].ytype; ytype {
case "Yrl":
arg.ytype = "Yml"
case "Yxr":
arg.ytype = "Yxm"
case "YxrEvex":
arg.ytype = "YxmEvex"
case "Yyr":
arg.ytype = "Yym"
case "YyrEvex":
arg.ytype = "YymEvex"
case "Yzr":
arg.ytype = "Yzm"
case "Yk":
arg.ytype = "Ykm"
default:
log.Fatalf("%s: unexpected register type: %s", r, ytype)
}
// Merge EVEX flags into m.
m.enc.evex.SAE = m.enc.evex.SAE || r.enc.evex.SAE
m.enc.evex.Rounding = m.enc.evex.Rounding || r.enc.evex.Rounding
m.enc.evex.Zeroing = m.enc.evex.Zeroing || r.enc.evex.Zeroing
delete(regOnly, k)
}
list = append(list, m)
}
for _, r := range regOnly {
list = append(list, r)
}
g.list = list
}
}
// mergeWIG merges [E]VEX.W0 + [E]VEX.W1 into [E]VEX.WIG.
func mergeWIG(ctx *context) {
mergeKey := func(inst *instruction) string {
return strings.Join([]string{
fmt.Sprint(len(inst.args)),
inst.enc.opbyte,
inst.enc.opdigit,
inst.enc.vex.P,
inst.enc.vex.L,
inst.enc.vex.M,
}, " ")
}
for _, g := range ctx.groups {
w0map := make(map[string]*instruction)
w1map := make(map[string]*instruction)
list := g.list[:0]
for _, inst := range g.list {
switch w := inst.enc.vex.W; w {
case "evexW0", "vexW0":
w0map[mergeKey(inst)] = inst
case "evexW1", "vexW1":
w1map[mergeKey(inst)] = inst
default:
log.Fatalf("%s: unexpected vex.W: %s", inst, w)
}
}
for k, w0 := range w0map {
w1 := w1map[k]
if w1 != nil {
w0.enc.vex.W = strings.Replace(w0.enc.vex.W, "W0", "WIG", 1)
delete(w1map, k)
}
list = append(list, w0)
}
for _, w1 := range w1map {
list = append(list, w1)
}
g.list = list
}
}
// assignZforms initializes zform field of every instruction in ctx.
func assignZforms(ctx *context) {
for _, g := range ctx.groups {
for _, inst := range g.list {
var parts []string
if inst.pset.Is("EVEX") {
parts = append(parts, "evex")
}
for _, arg := range inst.args {
parts = append(parts, arg.zkind)
}
if inst.enc.opdigit != "" {
parts = append(parts, "opdigit")
}
inst.zform = strings.Join(parts, " ")
}
}
}
// sortGroups sorts each instruction group by opcode as well as instructions
// inside groups by special rules (see below).
//
// The order of instructions inside group determine ytab
// elements order inside ytabList.
//
// We want these rules to be satisfied:
// - EVEX-encoded entries go after VEX-encoded entries.
// This way, VEX forms are selected over EVEX variants.
// - EVEX forms with SAE/RC must go before forms without them.
// This helps to avoid problems with reg-reg instructions
// that encode either of them in ModRM.R/M which causes
// ambiguity in ytabList (more than 1 ytab can match args).
// If first matching ytab has SAE/RC, problem will not occur.
// - Memory argument position affects order.
// Required to be in sync with XED encoder when there
// are multiple choices of how to encode instruction.
func sortGroups(ctx *context) {
sort.SliceStable(ctx.groups, func(i, j int) bool {
return ctx.groups[i].opcode < ctx.groups[j].opcode
})
for _, g := range ctx.groups {
sortInstList(g.list)
}
}
func sortInstList(insts []*instruction) {
// Use strings for sorting to get reliable transitive "less".
order := make(map[*instruction]string)
for _, inst := range insts {
encTag := 'a'
if inst.pset.Is("EVEX") {
encTag = 'b'
}
memTag := 'a'
if index := inst.ArgIndexByZkind("reg/mem"); index != -1 {
memTag = 'z' - rune(index)
}
rcsaeTag := 'a'
if !(inst.enc.evex.SAE || inst.enc.evex.Rounding) {
rcsaeTag = 'b'
}
order[inst] = fmt.Sprintf("%c%c%c %s",
encTag, memTag, rcsaeTag, inst.YtypeListString())
}
sort.SliceStable(insts, func(i, j int) bool {
return order[insts[i]] < order[insts[j]]
})
}
// addGoSuffixes splits some groups into several groups by introducing a suffix.
// For example, ANDN group becomes ANDNL and ANDNQ (ANDN becomes empty itself).
// Empty groups are removed.
func addGoSuffixes(ctx *context) {
var opcodeSuffixMatchers map[string][]string
{
opXY := []string{"VL=0", "X", "VL=1", "Y"}
opXYZ := []string{"VL=0", "X", "VL=1", "Y", "VL=2", "Z"}
opQ := []string{"REXW=1", "Q"}
opLQ := []string{"REXW=0", "L", "REXW=1", "Q"}
opcodeSuffixMatchers = map[string][]string{
"VCVTPD2DQ": opXY,
"VCVTPD2PS": opXY,
"VCVTTPD2DQ": opXY,
"VCVTQQ2PS": opXY,
"VCVTUQQ2PS": opXY,
"VCVTPD2UDQ": opXY,
"VCVTTPD2UDQ": opXY,
"VFPCLASSPD": opXYZ,
"VFPCLASSPS": opXYZ,
"VCVTSD2SI": opQ,
"VCVTTSD2SI": opQ,
"VCVTTSS2SI": opQ,
"VCVTSS2SI": opQ,
"VCVTSD2USI": opLQ,
"VCVTSS2USI": opLQ,
"VCVTTSD2USI": opLQ,
"VCVTTSS2USI": opLQ,
"VCVTUSI2SD": opLQ,
"VCVTUSI2SS": opLQ,
"VCVTSI2SD": opLQ,
"VCVTSI2SS": opLQ,
"ANDN": opLQ,
"BEXTR": opLQ,
"BLSI": opLQ,
"BLSMSK": opLQ,
"BLSR": opLQ,
"BZHI": opLQ,
"MULX": opLQ,
"PDEP": opLQ,
"PEXT": opLQ,
"RORX": opLQ,
"SARX": opLQ,
"SHLX": opLQ,
"SHRX": opLQ,
}
}
newGroups := make(map[string][]*instruction)
for _, g := range ctx.groups {
kv := opcodeSuffixMatchers[g.opcode]
if kv == nil {
continue
}
list := g.list[:0]
for _, inst := range g.list {
newOp := inst.opcode + inst.pset.Match(kv...)
if newOp != inst.opcode {
inst.opcode = newOp
newGroups[newOp] = append(newGroups[newOp], inst)
} else {
list = append(list, inst)
}
}
g.list = list
}
groups := ctx.groups[:0] // Filled with non-empty groups
// Some groups may become empty due to opcode split.
for _, g := range ctx.groups {
if len(g.list) != 0 {
groups = append(groups, g)
}
}
for op, insts := range newGroups {
groups = append(groups, &instGroup{
opcode: op,
list: insts,
})
}
ctx.groups = groups
}
func printTables(ctx *context) {
writeTables(os.Stdout, ctx)
}
@@ -0,0 +1,116 @@
// Copyright 2018 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 main
import (
"bytes"
"go/format"
"io"
"log"
"sort"
"text/template"
)
var tablesTemplate = template.Must(template.New("avx_optabs").Parse(`
// Code generated by x86avxgen. DO NOT EDIT.
package x86
// VEX instructions that come in two forms:
// VTHING xmm2/m128, xmmV, xmm1
// VTHING ymm2/m256, ymmV, ymm1
//
// The opcode array in the corresponding Optab entry
// should contain the (VEX prefixes, opcode byte) pair
// for each of the two forms.
// For example, the entries for VPXOR are:
//
// VPXOR xmm2/m128, xmmV, xmm1
// VEX.NDS.128.66.0F.WIG EF /r
//
// VPXOR ymm2/m256, ymmV, ymm1
// VEX.NDS.256.66.0F.WIG EF /r
//
// Produce this optab entry:
//
// {AVPXOR, yvex_xy3, Pavx, opBytes{vex128|vex66|vex0F|vexWIG, 0xEF, vex256|vex66|vex0F|vexWIG, 0xEF}}
//
// VEX requires at least 2 bytes inside opBytes:
// - VEX prefixes (vex-prefixed constants)
// - Opcode byte
//
// EVEX instructions extend VEX form variety:
// VTHING zmm2/m512, zmmV, zmm1 -- implicit K0 (merging)
// VTHING zmm2/m512, zmmV, K, zmm1 -- explicit K mask (can't use K0)
//
// EVEX requires at least 3 bytes inside opBytes:
// - EVEX prefixes (evex-prefixed constants); similar to VEX
// - Displacement multiplier info (scale / broadcast scale)
// - Opcode byte; similar to VEX
//
// Both VEX and EVEX instructions may have opdigit (opcode extension) byte
// which follows the primary opcode byte.
// Because it can only have value of 0-7, it is written in octal notation.
//
// x86.csv can be very useful for figuring out proper [E]VEX parts.
{{ range .Ylists }}
var {{.Name}} = []ytab{
{{- range .Ytabs }}
{zcase: {{.Zcase}}, zoffset: {{.Zoffset}}, args: argList{ {{.ArgList}} }},
{{- end }}
}
{{ end }}
var avxOptab = [...]Optab{
{{- range .Optabs }}
{as: {{.Opcode}}, ytab: {{.YtabList.Name}}, prefix: Pavx, op: opBytes{
{{- range .OpLines }}
{{.}},
{{- end }}
}},
{{- end }}
}
`))
// writeTables writes avx optabs file contents to w.
func writeTables(w io.Writer, ctx *context) {
ylists := make([]*ytabList, 0, len(ctx.ytabLists))
for _, ylist := range ctx.ytabLists {
ylists = append(ylists, ylist)
}
sort.Slice(ylists, func(i, j int) bool {
return ylists[i].Name < ylists[j].Name
})
optabs := make([]*optab, 0, len(ctx.optabs))
for _, o := range ctx.optabs {
optabs = append(optabs, o)
}
sort.Slice(optabs, func(i, j int) bool {
return optabs[i].Opcode < optabs[j].Opcode
})
var buf bytes.Buffer
err := tablesTemplate.Execute(&buf, struct {
Ylists []*ytabList
Optabs []*optab
}{
Ylists: ylists,
Optabs: optabs,
})
if err != nil {
log.Fatalf("template execute error: %v", err)
}
// TODO: invoke "go fmt" or format.Gofmt? #22695.
prettyCode, err := format.Source(buf.Bytes())
if err != nil {
log.Fatalf("gofmt error: %v", err)
}
if _, err := w.Write(prettyCode); err != nil {
log.Fatalf("write output: %v", err)
}
}
@@ -0,0 +1,160 @@
var _yvmovsd = []ytab{
{zcase: Zvex_r_v_rm, zoffset: 2, args: argList{Yxr, Yxr, Yxr}},
{zcase: Zvex_r_v_rm, zoffset: 2, args: argList{Yxr, Ym}},
{zcase: Zvex_rm_v_r, zoffset: 2, args: argList{Ym, Yxr}},
{zcase: Zvex_rm_v_r, zoffset: 2, args: argList{Yxr, Yxr, Yxr}},
{zcase: Zevex_r_v_rm, zoffset: 0, args: argList{YxrEvex, YxrEvex, YxrEvex}},
{zcase: Zevex_r_v_k_rm, zoffset: 3, args: argList{YxrEvex, YxrEvex, Yknot0, YxrEvex}},
{zcase: Zevex_r_v_rm, zoffset: 0, args: argList{YxrEvex, Ym}},
{zcase: Zevex_r_k_rm, zoffset: 3, args: argList{YxrEvex, Yknot0, Ym}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{Ym, YxrEvex}},
{zcase: Zevex_rm_k_r, zoffset: 3, args: argList{Ym, Yknot0, YxrEvex}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{YxrEvex, YxrEvex, YxrEvex}},
{zcase: Zevex_rm_v_k_r, zoffset: 3, args: argList{YxrEvex, YxrEvex, Yknot0, YxrEvex}},
}
----
{as: AVMOVSD, ytab: _yvmovsd, prefix: Pavx, op: opBytes{
avxEscape | vex128 | vexF2 | vex0F | vexW0, 0x11,
avxEscape | vex128 | vexF2 | vex0F | vexW0, 0x11,
avxEscape | vex128 | vexF2 | vex0F | vexW0, 0x10,
avxEscape | vex128 | vexF2 | vex0F | vexW0, 0x10,
avxEscape | evex128 | evexF2 | evex0F | evexW1, evexZeroingEnabled, 0x11,
avxEscape | evex128 | evexF2 | evex0F | evexW1, evexN8, 0x11,
avxEscape | evex128 | evexF2 | evex0F | evexW1, evexN8 | evexZeroingEnabled, 0x10,
avxEscape | evex128 | evexF2 | evex0F | evexW1, evexZeroingEnabled, 0x10,
}}
======
var _yvaddpd = []ytab{
{zcase: Zvex_rm_v_r, zoffset: 2, args: argList{Yxm, Yxr, Yxr}},
{zcase: Zvex_rm_v_r, zoffset: 2, args: argList{Yym, Yyr, Yyr}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{Yzm, Yzr, Yzr}},
{zcase: Zevex_rm_v_k_r, zoffset: 3, args: argList{Yzm, Yzr, Yknot0, Yzr}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{YxmEvex, YxrEvex, YxrEvex}},
{zcase: Zevex_rm_v_k_r, zoffset: 3, args: argList{YxmEvex, YxrEvex, Yknot0, YxrEvex}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{YymEvex, YyrEvex, YyrEvex}},
{zcase: Zevex_rm_v_k_r, zoffset: 3, args: argList{YymEvex, YyrEvex, Yknot0, YyrEvex}},
}
----
{as: AVADDPD, ytab: _yvaddpd, prefix: Pavx, op: opBytes{
avxEscape | vex128 | vex66 | vex0F | vexW0, 0x58,
avxEscape | vex256 | vex66 | vex0F | vexW0, 0x58,
avxEscape | evex512 | evex66 | evex0F | evexW1, evexN64 | evexBcstN8 | evexRoundingEnabled | evexZeroingEnabled, 0x58,
avxEscape | evex128 | evex66 | evex0F | evexW1, evexN16 | evexBcstN8 | evexZeroingEnabled, 0x58,
avxEscape | evex256 | evex66 | evex0F | evexW1, evexN32 | evexBcstN8 | evexZeroingEnabled, 0x58,
}}
======
var _yvcmppd = []ytab{
{zcase: Zvex_i_rm_v_r, zoffset: 2, args: argList{Yu8, Yxm, Yxr, Yxr}},
{zcase: Zvex_i_rm_v_r, zoffset: 2, args: argList{Yu8, Yym, Yyr, Yyr}},
{zcase: Zevex_i_rm_v_r, zoffset: 0, args: argList{Yu8, Yzm, Yzr, Yk}},
{zcase: Zevex_i_rm_v_k_r, zoffset: 3, args: argList{Yu8, Yzm, Yzr, Yknot0, Yk}},
{zcase: Zevex_i_rm_v_r, zoffset: 0, args: argList{Yu8, YxmEvex, YxrEvex, Yk}},
{zcase: Zevex_i_rm_v_k_r, zoffset: 3, args: argList{Yu8, YxmEvex, YxrEvex, Yknot0, Yk}},
{zcase: Zevex_i_rm_v_r, zoffset: 0, args: argList{Yu8, YymEvex, YyrEvex, Yk}},
{zcase: Zevex_i_rm_v_k_r, zoffset: 3, args: argList{Yu8, YymEvex, YyrEvex, Yknot0, Yk}},
}
----
{as: AVCMPPD, ytab: _yvcmppd, prefix: Pavx, op: opBytes{
avxEscape | vex128 | vex66 | vex0F | vexW0, 0xC2,
avxEscape | vex256 | vex66 | vex0F | vexW0, 0xC2,
avxEscape | evex512 | evex66 | evex0F | evexW1, evexN64 | evexBcstN8 | evexSaeEnabled, 0xC2,
avxEscape | evex128 | evex66 | evex0F | evexW1, evexN16 | evexBcstN8, 0xC2,
avxEscape | evex256 | evex66 | evex0F | evexW1, evexN32 | evexBcstN8, 0xC2,
}}
======
var _yvmovapd = []ytab{
{zcase: Zvex_r_v_rm, zoffset: 2, args: argList{Yxr, Yxm}},
{zcase: Zvex_r_v_rm, zoffset: 2, args: argList{Yyr, Yym}},
{zcase: Zvex_rm_v_r, zoffset: 2, args: argList{Yxm, Yxr}},
{zcase: Zvex_rm_v_r, zoffset: 2, args: argList{Yym, Yyr}},
{zcase: Zevex_r_v_rm, zoffset: 0, args: argList{YxrEvex, YxmEvex}},
{zcase: Zevex_r_k_rm, zoffset: 3, args: argList{YxrEvex, Yknot0, YxmEvex}},
{zcase: Zevex_r_v_rm, zoffset: 0, args: argList{YyrEvex, YymEvex}},
{zcase: Zevex_r_k_rm, zoffset: 3, args: argList{YyrEvex, Yknot0, YymEvex}},
{zcase: Zevex_r_v_rm, zoffset: 0, args: argList{Yzr, Yzm}},
{zcase: Zevex_r_k_rm, zoffset: 3, args: argList{Yzr, Yknot0, Yzm}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{YxmEvex, YxrEvex}},
{zcase: Zevex_rm_k_r, zoffset: 3, args: argList{YxmEvex, Yknot0, YxrEvex}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{YymEvex, YyrEvex}},
{zcase: Zevex_rm_k_r, zoffset: 3, args: argList{YymEvex, Yknot0, YyrEvex}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{Yzm, Yzr}},
{zcase: Zevex_rm_k_r, zoffset: 3, args: argList{Yzm, Yknot0, Yzr}},
}
----
{as: AVMOVAPD, ytab: _yvmovapd, prefix: Pavx, op: opBytes{
avxEscape | vex128 | vex66 | vex0F | vexW0, 0x29,
avxEscape | vex256 | vex66 | vex0F | vexW0, 0x29,
avxEscape | vex128 | vex66 | vex0F | vexW0, 0x28,
avxEscape | vex256 | vex66 | vex0F | vexW0, 0x28,
avxEscape | evex128 | evex66 | evex0F | evexW1, evexN16 | evexZeroingEnabled, 0x29,
avxEscape | evex256 | evex66 | evex0F | evexW1, evexN32 | evexZeroingEnabled, 0x29,
avxEscape | evex512 | evex66 | evex0F | evexW1, evexN64 | evexZeroingEnabled, 0x29,
avxEscape | evex128 | evex66 | evex0F | evexW1, evexN16 | evexZeroingEnabled, 0x28,
avxEscape | evex256 | evex66 | evex0F | evexW1, evexN32 | evexZeroingEnabled, 0x28,
avxEscape | evex512 | evex66 | evex0F | evexW1, evexN64 | evexZeroingEnabled, 0x28,
}}
======
var _yvpslld = []ytab{
{zcase: Zvex_i_rm_vo, zoffset: 3, args: argList{Yu8, Yxr, Yxr}},
{zcase: Zvex_i_rm_vo, zoffset: 3, args: argList{Yu8, Yyr, Yyr}},
{zcase: Zvex_rm_v_r, zoffset: 2, args: argList{Yxm, Yxr, Yxr}},
{zcase: Zvex_rm_v_r, zoffset: 2, args: argList{Yxm, Yyr, Yyr}},
{zcase: Zevex_i_rm_vo, zoffset: 0, args: argList{Yu8, YxmEvex, YxrEvex}},
{zcase: Zevex_i_rm_k_vo, zoffset: 4, args: argList{Yu8, YxmEvex, Yknot0, YxrEvex}},
{zcase: Zevex_i_rm_vo, zoffset: 0, args: argList{Yu8, YymEvex, YyrEvex}},
{zcase: Zevex_i_rm_k_vo, zoffset: 4, args: argList{Yu8, YymEvex, Yknot0, YyrEvex}},
{zcase: Zevex_i_rm_vo, zoffset: 0, args: argList{Yu8, Yzm, Yzr}},
{zcase: Zevex_i_rm_k_vo, zoffset: 4, args: argList{Yu8, Yzm, Yknot0, Yzr}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{YxmEvex, YxrEvex, YxrEvex}},
{zcase: Zevex_rm_v_k_r, zoffset: 3, args: argList{YxmEvex, YxrEvex, Yknot0, YxrEvex}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{YxmEvex, YyrEvex, YyrEvex}},
{zcase: Zevex_rm_v_k_r, zoffset: 3, args: argList{YxmEvex, YyrEvex, Yknot0, YyrEvex}},
{zcase: Zevex_rm_v_r, zoffset: 0, args: argList{YxmEvex, Yzr, Yzr}},
{zcase: Zevex_rm_v_k_r, zoffset: 3, args: argList{YxmEvex, Yzr, Yknot0, Yzr}},
}
----
{as: AVPSLLW, ytab: _yvpslld, prefix: Pavx, op: opBytes{
avxEscape | vex128 | vex66 | vex0F | vexW0, 0x71, 06,
avxEscape | vex256 | vex66 | vex0F | vexW0, 0x71, 06,
avxEscape | vex128 | vex66 | vex0F | vexW0, 0xF1,
avxEscape | vex256 | vex66 | vex0F | vexW0, 0xF1,
avxEscape | evex128 | evex66 | evex0F | evexW0, evexN16 | evexZeroingEnabled, 0x71, 06,
avxEscape | evex256 | evex66 | evex0F | evexW0, evexN32 | evexZeroingEnabled, 0x71, 06,
avxEscape | evex512 | evex66 | evex0F | evexW0, evexN64 | evexZeroingEnabled, 0x71, 06,
avxEscape | evex128 | evex66 | evex0F | evexW0, evexN16 | evexZeroingEnabled, 0xF1,
avxEscape | evex256 | evex66 | evex0F | evexW0, evexN16 | evexZeroingEnabled, 0xF1,
avxEscape | evex512 | evex66 | evex0F | evexW0, evexN16 | evexZeroingEnabled, 0xF1,
}}
======
var _yvzeroall = []ytab{
{zcase: Zvex, zoffset: 2, args: argList{}},
}
----
{as: AVZEROALL, ytab: _yvzeroall, prefix: Pavx, op: opBytes{
avxEscape | vex256 | vex0F | vexW0, 0x77,
}}
======
var _yvzeroall = []ytab{
{zcase: Zvex, zoffset: 2, args: argList{}},
}
----
{as: AVZEROUPPER, ytab: _yvzeroall, prefix: Pavx, op: opBytes{
avxEscape | vex128 | vex0F | vexW0, 0x77,
}}
======
var _yvcomisd = []ytab{
{zcase: Zvex_rm_v_r, zoffset: 2, args: argList{Yxm, Yxr}},
{zcase: Zevex_rm_v_r, zoffset: 3, args: argList{YxmEvex, YxrEvex}},
}
----
{as: AVUCOMISD, ytab: _yvcomisd, prefix: Pavx, op: opBytes{
avxEscape | vex128 | vex66 | vex0F | vexW0, 0x2E,
avxEscape | evex128 | evex66 | evex0F | evexW1, evexN8 | evexSaeEnabled, 0x2E,
}}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,69 @@
###FILE: ./datafiles/xed-operand-types.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
#
#
#XTYPE TYPE BITS-PER-ELEM
#
var VARIABLE 0 # instruction must set NELEM and ELEMENT_SIZE
struct STRUCT 0 # many elements of different widths
int INT 0 # one element, all the bits, width varies
uint UINT 0 # one element, all the bits, width varies
#
i1 INT 1
i8 INT 8
i16 INT 16
i32 INT 32
i64 INT 64
u8 UINT 8
u16 UINT 16
u32 UINT 32
u64 UINT 64
u128 UINT 128
u256 UINT 256
f32 SINGLE 32
f64 DOUBLE 64
f80 LONGDOUBLE 80
b80 LONGBCD 80
###FILE: ./datafiles/ivbavx/fp16-operand-types.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
#XTYPE TYPE BITS-PER-ELEM
f16 FLOAT16 16
@@ -0,0 +1,341 @@
###FILE: ./datafiles/xed-state-bits.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
###########################################################################
## file: xed-state-bits.txt
###########################################################################
# These are just shorthand for some conditions or captures.
# Simple macro replacement
#all_modes ALL_MODES=1
not64 MODE!=2
mode64 MODE=2
mode32 MODE=1
mode16 MODE=0
# effective addressing mode
eanot16 EASZ!=1
eamode16 EASZ=1
eamode32 EASZ=2
eamode64 EASZ=3
# stack addressing mode
smode16 SMODE=0
smode32 SMODE=1
smode64 SMODE=2
eosz8 EOSZ=0
eosz16 EOSZ=1
not_eosz16 EOSZ!=1
eosz32 EOSZ=2
eosz64 EOSZ=3
eosznot64 EOSZ!=3
# for OD expansion in graph partitioning FIXME
mod0 MOD=0
mod1 MOD=1
mod2 MOD=2
mod3 MOD=3
rex_reqd REX=1
no_rex REX=0
reset_rex REX=0 REXW=0 REXB=0 REXR=0 REXX=0
rexb_prefix REXB=1
rexx_prefix REXX=1
rexr_prefix REXR=1
# 2013-09-25 FIXME: we were inconsistent. some things use W0/W1, some
# use the more verbose form. We should converge on W0/W1.
#
rexw_prefix REXW=1 SKIP_OSZ=1
norexw_prefix REXW=0 SKIP_OSZ=1
W1 REXW=1 SKIP_OSZ=1
W0 REXW=0 SKIP_OSZ=1
norexb_prefix REXB=0
norexx_prefix REXX=0
norexr_prefix REXR=0
############################################################3333
f2_prefix REP=2 # REPNZ, REPNE
f3_prefix REP=3 # REPZ, REPE
repne REP=2
repe REP=3
norep REP=0
66_prefix OSZ=1
nof3_prefix REP!=3
no66_prefix OSZ=0
not_refining REP=0 # dummy setting for state values 2007-08-06 FIXME
refining_f2 REP=2
refining_f3 REP=3
not_refining_f3 REP!=3 # for pause vs xchg
no_refining_prefix REP=0 OSZ=0 # critical:REP must be first for decoding partitioning
osz_refining_prefix REP=0 OSZ=1
f2_refining_prefix REP=2
f3_refining_prefix REP=3
no67_prefix ASZ=0
67_prefix ASZ=1
lock_prefix LOCK=1
nolock_prefix LOCK=0
default_ds DEFAULT_SEG=0
default_ss DEFAULT_SEG=1
default_es DEFAULT_SEG=2 # for string ops
no_seg_prefix SEG_OVD=0
some_seg_prefix SEG_OVD!=0
cs_prefix SEG_OVD=1
ds_prefix SEG_OVD=2
es_prefix SEG_OVD=3
fs_prefix SEG_OVD=4
gs_prefix SEG_OVD=5
ss_prefix SEG_OVD=6
# default (or not) to 64b width in 64b mode
nrmw DF64=0
df64 DF64=1
# default choice for encoder when there are multiple choices for a
# nonterminal. The ISA is not uniquely determined for encoding so we
# must express preferences for certain forms!
enc ENCODER_PREFERRED=1
# for the legacy prefix encoder, tell it to keep trying rules and not
# return after successfully finding one that applies
no_return NO_RETURN=1
# indicate an encoding or decoding error occurred
error ERROR=XED_ERROR_GENERAL_ERROR
# dummy constraint which always satisfies
true DUMMY=0
###FILE: ./datafiles/amdxop/xop-state-bits.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
XMAP8 MAP=8
XMAP9 MAP=9
XMAPA MAP=10
XOPV VEXVALID=3
###FILE: ./datafiles/avx/avx-state-bits.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
VL128 VL=0
VL256 VL=1
VV1 VEXVALID=1
VV0 VEXVALID=0
VMAP0 MAP=0
V0F MAP=1
V0F38 MAP=2
V0F3A MAP=3
VNP VEX_PREFIX=0
V66 VEX_PREFIX=1
VF2 VEX_PREFIX=2
VF3 VEX_PREFIX=3
# No VEX-SPECIFIED-REGISTER
NOVSR VEXDEST3=0b1 VEXDEST210=0b111
EMX_BROADCAST_1TO4_32 BCAST=10 # 128
EMX_BROADCAST_1TO4_64 BCAST=13 # 256
EMX_BROADCAST_1TO8_32 BCAST=3 # 256
EMX_BROADCAST_2TO4_64 BCAST=20 # 256
###FILE: ./datafiles/avxhsw/hsw-state-bits.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
EMX_BROADCAST_1TO2_64 BCAST=11 # 128
EMX_BROADCAST_1TO8_16 BCAST=14 # 128
EMX_BROADCAST_1TO16_16 BCAST=15 # 256
EMX_BROADCAST_1TO16_8 BCAST=17 # 128
EMX_BROADCAST_1TO32_8 BCAST=18 # 256
###FILE: /home/quasilyte/CODE/intel/xed/datafiles/knc/uisa-state-bits.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
VL512 VL=2
VLBAD VL=3 # unused VL setting to cause things not to decode.
# KNC EVEX is KVV
#
KVV VEXVALID=4
# No VEX-SPECIFIED-REGISTER
NOEVSR VEXDEST3=0b1 VEXDEST210=0b111 VEXDEST4=0b0
# No VEX-SPECIFIED-REGISTER for GATHERS/SCATTERS -- index reg 5th bit is VEXTDEST4
NO_SPARSE_EVSR VEXDEST3=0b1 VEXDEST210=0b111
# These conflict w/another chip ... so if you ever build a combo
# model you'll have to remove these somehow.
#
EMX_BROADCAST_1TO16_32 BCAST=1 # 512
EMX_BROADCAST_4TO16_32 BCAST=2 # 512
EMX_BROADCAST_1TO8_64 BCAST=5 # 512
EMX_BROADCAST_4TO8_64 BCAST=6 # 512
###FILE: ./datafiles/avx512f/avx512-state-bits.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
EVV VEXVALID=2
EMX_BROADCAST_1TO16_32 BCAST=1 # 512
EMX_BROADCAST_4TO16_32 BCAST=2 # 512
EMX_BROADCAST_1TO8_64 BCAST=5 # 512
EMX_BROADCAST_4TO8_64 BCAST=6 # 512
EMX_BROADCAST_2TO16_32 BCAST=7 # 512
EMX_BROADCAST_2TO8_64 BCAST=8 # 512
EMX_BROADCAST_8TO16_32 BCAST=9 # 512
EMX_BROADCAST_1TO32_16 BCAST=16 # 512
EMX_BROADCAST_1TO64_8 BCAST=19 # 512
# these do not show up on earlier processors
EMX_BROADCAST_4TO8_32 BCAST=4 # 256
EMX_BROADCAST_2TO4_32 BCAST=12 # 128
EMX_BROADCAST_2TO8_32 BCAST=21 # 256
EMX_BROADCAST_1TO2_32 BCAST=22 # 128
###FILE: ./datafiles/avx512-skx/skx-state-bits.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
EMX_BROADCAST_1TO2_8 BCAST=23
EMX_BROADCAST_1TO4_8 BCAST=24
EMX_BROADCAST_1TO8_8 BCAST=25
EMX_BROADCAST_1TO2_16 BCAST=26
EMX_BROADCAST_1TO4_16 BCAST=27
@@ -0,0 +1,224 @@
###FILE: ./datafiles/xed-operand-width.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
# @file xed-operand-width.txt
# the default xtype can be overridden in each operand using a ":" followed by an explicit xtype
##
## the width defaults to bytes. But it can be bits if it has a "bits" suffix
##
#
# default
#oc2-code XTYPE width16 width32 width64 (if only one width is shown, it is for all widths)
#
INVALID INVALID 0
#
# 3 strange things:
#
asz int 2 4 8 # varies with the effective address width
ssz int 2 4 8 # varies with the stack address width
pseudo struct 0 # these are for unusual registers
pseudox87 struct 0 # these are for unusual registers
#
#
#
#1 i1 1 # FIXME: this is not used...
a16 i16 4 # bound
a32 i32 8 # bound
b u8 1
d i32 4
#
i8 i8 1
u8 u8 1
i16 i16 2
u16 u16 2
i32 i32 4
u32 u32 4
i64 i64 8
u64 u64 8
f16 f16 2 # IVB converts
f32 f32 4
f64 f64 8
#
dq i32 16
#
xub u8 16
xuw u16 16
xud u32 16
xuq u64 16
x128 u128 16
#
xb i8 16
xw i16 16
xd i32 16
xq i64 16
#
#
mb i8 8
mw i16 8
md i32 8
mq i64 8
#
m64int i64 8
m64real f64 8
mem108 struct 108
mem14 struct 14
mem16 struct 2
mem16int i16 2
mem28 struct 28
mem32int i32 4
mem32real f32 4
mem80dec b80 10
mem80real f80 10
f80 f80 10 # for X87 registers:
mem94 struct 94
mfpxenv struct 512
mxsave struct 576
mprefetch i64 64 # made up width for prefetches
p struct 4 6 6
p2 struct 4 6 10
pd f64 16
ps f32 16
pi i32 8
q i64 8
s struct 6 6 10
s64 struct 10
sd f64 8
si i32 4
ss f32 4
v int 2 4 8
y int 4 4 8
w i16 2
z int 2 4 4
spw8 int 16 32 0 # varies (64b invalid) STACK POINTER WIDTH
spw int 2 4 8 # varies STACK POINTER WIDTH
spw5 int 10 20 40 # varies (IRET approx) STACK POINTER WIDTH
spw3 int 6 12 24 # varies (IRET approx) STACK POINTER WIDTH
spw2 int 4 8 16 # varies (FAR call/ret approx) STACK POINTER WIDTH
i1 int 1bits
i2 int 2bits
i3 int 3bits
i4 int 4bits
i5 int 5bits
i6 int 6bits
i7 int 7bits
i8 int 8bits
var var 0 # relies on NELEM * ELEMENT_SIZE to get the number of bits.
bnd32 u32 12 # MPX 32b BNDLDX/BNDSTX memop 3x4B
bnd64 u64 24 # MPX 32b BNDLDX/BNDSTX memop 3x8B
###FILE: ./datafiles/avx/avx-operand-width.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
#
#code XTYPE width16 width32 width64 (if only one width is presented, it is for all widths)
#
qq i32 32
yub u8 32
yuw u16 32
yud u32 32
yuq u64 32
y128 u128 32
yb i8 32
yw i16 32
yd i32 32
yq i64 32
yps f32 32
ypd f64 32
###FILE: ./datafiles/avx512f/avx512-operand-widths.txt
#BEGIN_LEGAL
#
#Copyright (c) 2016 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#END_LEGAL
#
#code XTYPE width16 width32 width64 (if only one width is presented, it is for all widths)
#
vv var 0 # relies on nelem * elem_size
zv var 0 # relies on nelem * elem_size
wrd u16 16bits
mskw i1 64bits # FIXME: bad name
zmskw i1 512bits
zf32 f32 512bits
zf64 f64 512bits
zb i8 512bits
zw i16 512bits
zd i32 512bits
zq i64 512bits
zub u8 512bits
zuw u16 512bits
zud u32 512bits
zuq u64 512bits
# alternative names...
zi8 i8 512bits
zi16 i16 512bits
zi32 i32 512bits
zi64 i64 512bits
zu8 u8 512bits
zu16 u16 512bits
zu32 u32 512bits
zu64 u64 512bits
zu128 u128 512bits