blob: e2f5b24de60eab596dfa330f1831c8a34cb3c8c2 [file] [log] [blame] [edit]
// 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)
}
}