diff options
Diffstat (limited to 'src/simd/archsimd/_gen/simdgen/xed.go')
| -rw-r--r-- | src/simd/archsimd/_gen/simdgen/xed.go | 125 |
1 files changed, 78 insertions, 47 deletions
diff --git a/src/simd/archsimd/_gen/simdgen/xed.go b/src/simd/archsimd/_gen/simdgen/xed.go index 4ba6738e7e..5d6fac64d0 100644 --- a/src/simd/archsimd/_gen/simdgen/xed.go +++ b/src/simd/archsimd/_gen/simdgen/xed.go @@ -5,7 +5,6 @@ package main import ( - "cmp" "fmt" "log" "maps" @@ -78,7 +77,7 @@ func loadXED(xedPath string) []*unify.Value { switch { case inst.RealOpcode == "N": return // Skip unstable instructions - case !(strings.HasPrefix(inst.Extension, "AVX") || strings.HasPrefix(inst.Extension, "SHA")): + case !(strings.HasPrefix(inst.Extension, "AVX") || strings.HasPrefix(inst.Extension, "SHA") || inst.Extension == "FMA"): // We're only interested in AVX and SHA instructions. return } @@ -210,16 +209,9 @@ func loadXED(xedPath string) []*unify.Value { } log.Printf("%d unhandled CPU features for %d instructions (use -v for details)", len(unknownFeatures), nInst) } else { - keys := slices.SortedFunc(maps.Keys(unknownFeatures), func(a, b cpuFeatureKey) int { - return cmp.Or(cmp.Compare(a.Extension, b.Extension), - cmp.Compare(a.ISASet, b.ISASet)) - }) + keys := slices.Sorted(maps.Keys(unknownFeatures)) for _, key := range keys { - if key.ISASet == "" || key.ISASet == key.Extension { - log.Printf("unhandled Extension %s", key.Extension) - } else { - log.Printf("unhandled Extension %s and ISASet %s", key.Extension, key.ISASet) - } + log.Printf("unhandled ISASet %s", key) log.Printf(" opcodes: %s", slices.Sorted(maps.Keys(unknownFeatures[key]))) } } @@ -763,16 +755,24 @@ func instToUVal1(inst *xeddata.Inst, ops []operand, feature string, variant inst // decodeCPUFeature returns the CPU feature name required by inst. These match // the names of the "Has*" feature checks in the simd package. func decodeCPUFeature(inst *xeddata.Inst) (string, bool) { - key := cpuFeatureKey{ - Extension: inst.Extension, - ISASet: isaSetStrip.ReplaceAllLiteralString(inst.ISASet, ""), + isaSet := inst.ISASet + if isaSet == "" { + // Older instructions don't have an ISA set. Use their "extension" + // instead. + isaSet = inst.Extension } - feat, ok := cpuFeatureMap[key] + // We require AVX512VL to use AVX512 at all, so strip off the vector length + // suffixes. + if strings.HasPrefix(isaSet, "AVX512") { + isaSet = isaSetVL.ReplaceAllLiteralString(isaSet, "") + } + + feat, ok := cpuFeatureMap[isaSet] if !ok { - imap := unknownFeatures[key] + imap := unknownFeatures[isaSet] if imap == nil { imap = make(map[string]struct{}) - unknownFeatures[key] = imap + unknownFeatures[isaSet] = imap } imap[inst.Opcode()] = struct{}{} return "", false @@ -783,45 +783,76 @@ func decodeCPUFeature(inst *xeddata.Inst) (string, bool) { return feat, true } -var isaSetStrip = regexp.MustCompile("_(128N?|256N?|512)$") +var isaSetVL = regexp.MustCompile("_(128N?|256N?|512)$") -type cpuFeatureKey struct { - Extension, ISASet string -} - -// cpuFeatureMap maps from XED's "EXTENSION" and "ISA_SET" to a CPU feature name -// that can be used in the SIMD API. -var cpuFeatureMap = map[cpuFeatureKey]string{ - {"SHA", "SHA"}: "SHA", - - {"AVX", ""}: "AVX", - {"AVX_VNNI", "AVX_VNNI"}: "AVXVNNI", - {"AVX2", ""}: "AVX2", - {"AVXAES", ""}: "AVX, AES", +// cpuFeatureMap maps from XED's "ISA_SET" (or "EXTENSION") to a CPU feature +// name to expose in the SIMD feature check API. +// +// See XED's datafiles/*/cpuid.xed.txt for how ISA set names map to CPUID flags. +var cpuFeatureMap = map[string]string{ + "AVX": "AVX", + "AVX_VNNI": "AVXVNNI", + "AVX2": "AVX2", + "AVXAES": "AVXAES", + "SHA": "SHA", + "FMA": "FMA", // AVX-512 foundational features. We combine all of these into one "AVX512" feature. - {"AVX512EVEX", "AVX512F"}: "AVX512", - {"AVX512EVEX", "AVX512CD"}: "AVX512", - {"AVX512EVEX", "AVX512BW"}: "AVX512", - {"AVX512EVEX", "AVX512DQ"}: "AVX512", - // AVX512VL doesn't appear explicitly in the ISASet. I guess it's implied by - // the vector length suffix. + "AVX512F": "AVX512", + "AVX512BW": "AVX512", + "AVX512CD": "AVX512", + "AVX512DQ": "AVX512", + // AVX512VL doesn't appear as its own ISASet; instead, the CPUID flag is + // required by the *_128 and *_256 ISASets. We fold it into "AVX512" anyway. // AVX-512 extension features - {"AVX512EVEX", "AVX512_BITALG"}: "AVX512BITALG", - {"AVX512EVEX", "AVX512_GFNI"}: "AVX512GFNI", - {"AVX512EVEX", "AVX512_VBMI2"}: "AVX512VBMI2", - {"AVX512EVEX", "AVX512_VBMI"}: "AVX512VBMI", - {"AVX512EVEX", "AVX512_VNNI"}: "AVX512VNNI", - {"AVX512EVEX", "AVX512_VPOPCNTDQ"}: "AVX512VPOPCNTDQ", - {"AVX512EVEX", "AVX512_VAES"}: "AVX512VAES", - {"AVX512EVEX", "AVX512_VPCLMULQDQ"}: "AVX512VPCLMULQDQ", + "AVX512_BITALG": "AVX512BITALG", + "AVX512_GFNI": "AVX512GFNI", + "AVX512_VBMI": "AVX512VBMI", + "AVX512_VBMI2": "AVX512VBMI2", + "AVX512_VNNI": "AVX512VNNI", + "AVX512_VPOPCNTDQ": "AVX512VPOPCNTDQ", + "AVX512_VAES": "AVX512VAES", + "AVX512_VPCLMULQDQ": "AVX512VPCLMULQDQ", // AVX 10.2 (not yet supported) - {"AVX512EVEX", "AVX10_2_RC"}: "ignore", + "AVX10_2_RC": "ignore", +} + +func init() { + // TODO: In general, Intel doesn't make any guarantees about what flags are + // set, so this means our feature checks need to ensure these, just to be + // sure. + var features = map[string]featureInfo{ + "AVX2": {Implies: []string{"AVX"}}, + "AVX512": {Implies: []string{"AVX2"}}, + + "AVXAES": {Virtual: true, Implies: []string{"AVX", "AES"}}, + "FMA": {Implies: []string{"AVX"}}, + + // AVX-512 subfeatures. + "AVX512BITALG": {Implies: []string{"AVX512"}}, + "AVX512GFNI": {Implies: []string{"AVX512"}}, + "AVX512VBMI": {Implies: []string{"AVX512"}}, + "AVX512VBMI2": {Implies: []string{"AVX512"}}, + "AVX512VNNI": {Implies: []string{"AVX512"}}, + "AVX512VPOPCNTDQ": {Implies: []string{"AVX512"}}, + "AVX512VAES": {Implies: []string{"AVX512"}}, + + // AVX-VNNI and AVX-IFMA are "backports" of the AVX512-VNNI/IFMA + // instructions to VEX encoding, limited to 256 bit vectors. They're + // intended for lower end CPUs that want to support VNNI/IFMA without + // supporting AVX-512. As such, they're built on AVX2's VEX encoding. + "AVXVNNI": {Implies: []string{"AVX2"}}, + "AVXIFMA": {Implies: []string{"AVX2"}}, + } + registerFeatureInfo("amd64", goarchFeatures{ + featureVar: "X86", + features: features, + }) } -var unknownFeatures = map[cpuFeatureKey]map[string]struct{}{} +var unknownFeatures = map[string]map[string]struct{}{} // hasOptionalMask returns whether there is an optional mask operand in ops. func hasOptionalMask(ops []operand) bool { |
