117 lines
2.2 KiB
Go
117 lines
2.2 KiB
Go
package inst
|
|
|
|
import (
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"golang.org/x/arch/x86/x86csv"
|
|
)
|
|
|
|
// ReadFromX86CSV reads instruction list from the Go "x86.csv" format.
|
|
func ReadFromX86CSV(r io.Reader) ([]Instruction, error) {
|
|
c := x86csv.NewReader(r)
|
|
|
|
rows, err := c.ReadAll()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Group by Go opcode.
|
|
groups := map[string][]*x86csv.Inst{}
|
|
for _, row := range rows {
|
|
g := row.GoOpcode()
|
|
groups[g] = append(groups[g], row)
|
|
}
|
|
|
|
var is []Instruction
|
|
for opcode, group := range groups {
|
|
i := Instruction{
|
|
Opcode: opcode,
|
|
}
|
|
for _, row := range group {
|
|
forms := formsFromRow(row)
|
|
i.Forms = append(i.Forms, forms...)
|
|
}
|
|
is = append(is, i)
|
|
}
|
|
|
|
return is, nil
|
|
}
|
|
|
|
func formsFromRow(row *x86csv.Inst) []Form {
|
|
var fs []Form
|
|
signatures := argsToSignatures(row.GoArgs())
|
|
for _, signature := range signatures {
|
|
ops := make([]Operand, len(signature))
|
|
for i, t := range signature {
|
|
ops[i] = Operand{
|
|
Type: t,
|
|
}
|
|
}
|
|
f := Form{
|
|
Operands: ops,
|
|
CPUID: splitCPUID(row.CPUID),
|
|
}
|
|
fs = append(fs, f)
|
|
}
|
|
return fs
|
|
}
|
|
|
|
func expandArg(arg string) []string {
|
|
mmprefixes := []string{"", "x", "y"}
|
|
|
|
for e := 8; e <= 512; e *= 2 {
|
|
s := strconv.Itoa(e)
|
|
switch arg {
|
|
case "r/m" + s:
|
|
return []string{"r" + s, "m" + s}
|
|
case "r" + s + "V":
|
|
return []string{"r" + s}
|
|
}
|
|
for _, p := range mmprefixes {
|
|
if arg == p+"mm2/m"+s {
|
|
return []string{p + "mm", "m" + s}
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, p := range []string{"", "x", "y"} {
|
|
switch arg {
|
|
case p + "mm1", p + "mm2", p + "mmV":
|
|
return []string{p + "mm"}
|
|
}
|
|
}
|
|
|
|
return []string{arg}
|
|
}
|
|
|
|
func argsToSignatures(args []string) [][]string {
|
|
n := len(args)
|
|
if n == 0 {
|
|
return [][]string{nil}
|
|
}
|
|
types := expandArg(args[n-1])
|
|
var expanded [][]string
|
|
for _, sub := range argsToSignatures(args[:n-1]) {
|
|
for _, t := range types {
|
|
f := make([]string, n-1, n)
|
|
copy(f, sub)
|
|
f = append(f, t)
|
|
expanded = append(expanded, f)
|
|
}
|
|
}
|
|
return expanded
|
|
}
|
|
|
|
// splitCPUID splits CPUID field into flags, plus handling a few oddities.
|
|
func splitCPUID(cpuid string) []string {
|
|
switch cpuid {
|
|
case "Both AES and AVX flags":
|
|
return []string{"AES", "AVX"}
|
|
case "HLE or RTM":
|
|
return []string{"HLE/RTM"}
|
|
}
|
|
return strings.Split(cpuid, ",")
|
|
}
|