all: add GFNI instructions (#344)

Adds support for the GFNI "Galois Field New Instructions" instruction set.

These instructions are not included in the Opcodes database, therefore they're
added using the "extras" mechanism introduced in #345.

For simplicity, the loading phase is updated slightly so that AVX-512 form
expansion rules are applied after extras are added to the list. This greatly
reduces the number of forms that have to be specified by hand.

Based on #343
Fixes #335

Co-authored-by: Klaus Post <klauspost@gmail.com>
This commit is contained in:
Michael McLoughlin
2022-11-27 18:53:46 -08:00
committed by GitHub
parent a0ea0f3e6f
commit 946323570a
10 changed files with 2362 additions and 398 deletions

View File

@@ -80,8 +80,7 @@ func (l *Loader) Load() ([]inst.Instruction, error) {
Summary: i.Summary,
}
}
forms := l.forms(opcode, f)
im[opcode].Forms = append(im[opcode].Forms, forms...)
im[opcode].Forms = append(im[opcode].Forms, l.form(opcode, f))
}
}
}
@@ -91,6 +90,11 @@ func (l *Loader) Load() ([]inst.Instruction, error) {
im[e.Opcode] = e
}
// Generate additional AVX-512 forms.
for _, i := range im {
i.Forms = avx512forms(i.Opcode, i.Forms)
}
// Merge aliased forms. This is primarily for MOVQ (issue #50).
for _, a := range aliases {
if existing, found := im[a.From]; found {
@@ -122,6 +126,7 @@ func (l *Loader) Load() ([]inst.Instruction, error) {
// Convert to a slice. Sort instructions and forms for reproducibility.
is := make([]inst.Instruction, 0, len(im))
for _, i := range im {
sortforms(i.Forms)
is = append(is, *i)
}
@@ -129,10 +134,6 @@ func (l *Loader) Load() ([]inst.Instruction, error) {
return is[i].Opcode < is[j].Opcode
})
for _, i := range im {
sortforms(i.Forms)
}
return is, nil
}
@@ -309,7 +310,7 @@ func (l Loader) gonames(f opcodesxml.Form) []string {
return []string{n}
}
func (l Loader) forms(opcode string, f opcodesxml.Form) []inst.Form {
func (l Loader) form(opcode string, f opcodesxml.Form) inst.Form {
// Map operands to avo format and ensure correct order.
ops := operands(f.Operands)
@@ -366,34 +367,14 @@ func (l Loader) forms(opcode string, f opcodesxml.Form) []inst.Form {
}
sort.Strings(isas)
// Initialize form.
form := inst.Form{
// Build form.
return inst.Form{
ISA: isas,
Operands: ops,
ImplicitOperands: implicits,
EncodingType: enctype(f),
CancellingInputs: f.CancellingInputs,
}
// Apply modification stages to produce final list of forms.
stages := []func(string, inst.Form) []inst.Form{
avx512rounding,
avx512sae,
avx512bcst,
avx512masking,
avx512zeroing,
}
forms := []inst.Form{form}
for _, stage := range stages {
var next []inst.Form
for _, f := range forms {
next = append(next, stage(opcode, f)...)
}
forms = next
}
return forms
}
// operands maps Opcodes XML operands to avo format. Returned in Intel order.
@@ -414,6 +395,31 @@ func operand(op opcodesxml.Operand) inst.Operand {
}
}
// avx512forms processes AVX-512 operands and expands them into additional
// instruction forms as expected by the Go assembler.
//
// See: https://go.dev/wiki/AVX512
func avx512forms(opcode string, forms []inst.Form) []inst.Form {
// Apply modification stages to produce final list of forms.
stages := []func(string, inst.Form) []inst.Form{
avx512rounding,
avx512sae,
avx512bcst,
avx512masking,
avx512zeroing,
}
for _, stage := range stages {
var next []inst.Form
for _, f := range forms {
next = append(next, stage(opcode, f)...)
}
forms = next
}
return forms
}
// avx512rounding handles AVX-512 embedded rounding. Opcodes database represents
// these as {er} operands, whereas Go uses instruction suffixes. Remove the
// operand if present and set the corresponding flag.
@@ -825,7 +831,6 @@ func vexevex(fs []inst.Form) ([]inst.Form, error) {
}
if group[0].EncodingType != inst.EncodingTypeVEX || group[1].EncodingType != inst.EncodingTypeEVEX {
fmt.Println(group)
return nil, errors.New("expected pair of VEX/EVEX encoded forms")
}