handle xmm instructions
This commit is contained in:
@@ -16,11 +16,16 @@ func (l LoaderTest) Generate(w io.Writer, is []*inst.Instruction) error {
|
|||||||
|
|
||||||
for _, i := range is {
|
for _, i := range is {
|
||||||
p.printf("\t// %s %s\n", i.Opcode, i.Summary)
|
p.printf("\t// %s %s\n", i.Opcode, i.Summary)
|
||||||
|
if strings.HasPrefix(i.Opcode, "RET") {
|
||||||
|
p.printf("\t// SKIP: early RET instruction would cause assembler error")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, f := range i.Forms {
|
for _, f := range i.Forms {
|
||||||
as := args(f.Operands)
|
as := args(f.Operands)
|
||||||
p.printf("\t// %#v\n", f.Operands)
|
p.printf("\t// %#v\n", f.Operands)
|
||||||
if as == nil {
|
if as == nil {
|
||||||
p.printf("\t// skip\n")
|
p.printf("\t// SKIP:\n")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.printf("\t%s\t%s\n", i.Opcode, strings.Join(as, ", "))
|
p.printf("\t%s\t%s\n", i.Opcode, strings.Join(as, ", "))
|
||||||
@@ -66,11 +71,10 @@ func arg(t string) string {
|
|||||||
// <xs:enumeration value="r32" />
|
// <xs:enumeration value="r32" />
|
||||||
// <xs:enumeration value="r32l" />
|
// <xs:enumeration value="r32l" />
|
||||||
// <xs:enumeration value="rax" />
|
// <xs:enumeration value="rax" />
|
||||||
// <xs:enumeration value="r64" />
|
"r64": "R15", // <xs:enumeration value="r64" />
|
||||||
"r64": "R8",
|
|
||||||
// <xs:enumeration value="mm" />
|
// <xs:enumeration value="mm" />
|
||||||
// <xs:enumeration value="xmm0" />
|
// <xs:enumeration value="xmm0" />
|
||||||
// <xs:enumeration value="xmm" />
|
"xmm": "X7", // <xs:enumeration value="xmm" />
|
||||||
// <xs:enumeration value="xmm{k}" />
|
// <xs:enumeration value="xmm{k}" />
|
||||||
// <xs:enumeration value="xmm{k}{z}" />
|
// <xs:enumeration value="xmm{k}{z}" />
|
||||||
// <xs:enumeration value="ymm" />
|
// <xs:enumeration value="ymm" />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package load
|
package load
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -81,16 +82,24 @@ func (l *Loader) init() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for a, op := range l.alias {
|
||||||
|
log.Printf("alias: %#v -> %s", a, op)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// include decides whether to include the instruction form in the avo listing.
|
// include decides whether to include the instruction form in the avo listing.
|
||||||
// This discards some opcodes that are not supported in Go.
|
// This discards some opcodes that are not supported in Go.
|
||||||
func (l Loader) include(f opcodesxml.Form) bool {
|
func (l Loader) include(f opcodesxml.Form) bool {
|
||||||
// Exclude certain ISAs simply not present in Go.
|
// Exclude certain ISAs simply not present in Go (AMD-only is a common reason).
|
||||||
for _, isa := range f.ISA {
|
for _, isa := range f.ISA {
|
||||||
switch isa.ID {
|
switch isa.ID {
|
||||||
case "TBM", "CLZERO", "MONITORX", "FEMMS":
|
case "TBM", "CLZERO", "MONITORX", "FEMMS", "FMA4", "XOP", "SSE4A":
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// TODO(mbm): support AVX512
|
||||||
|
if strings.HasPrefix(isa.ID, "AVX512") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,27 +122,32 @@ func (l Loader) include(f opcodesxml.Form) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l Loader) lookupAlias(f opcodesxml.Form) string {
|
func (l Loader) lookupAlias(f opcodesxml.Form) string {
|
||||||
a := opcodescsv.Alias{Opcode: f.GASName, DataSize: datasize(f)}
|
a := opcodescsv.Alias{
|
||||||
|
Opcode: f.GASName,
|
||||||
|
DataSize: datasize(f),
|
||||||
|
NumOperands: len(f.Operands),
|
||||||
|
}
|
||||||
return l.alias[a]
|
return l.alias[a]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l Loader) goname(f opcodesxml.Form) string {
|
func (l Loader) goname(f opcodesxml.Form) string {
|
||||||
// Use go opcode from Opcodes XML where available.
|
|
||||||
if f.GoName != "" {
|
|
||||||
return f.GoName
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return alias if available.
|
// Return alias if available.
|
||||||
if a := l.lookupAlias(f); a != "" {
|
if a := l.lookupAlias(f); a != "" {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use go opcode from Opcodes XML where available.
|
||||||
|
if f.GoName != "" {
|
||||||
|
return f.GoName
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to GAS name.
|
||||||
n := strings.ToUpper(f.GASName)
|
n := strings.ToUpper(f.GASName)
|
||||||
|
|
||||||
// Some need data sizes added to them.
|
// Some need data sizes added to them.
|
||||||
// TODO(mbm): is there a better way of determining which ones these are?
|
// TODO(mbm): is there a better way of determining which ones these are?
|
||||||
s := datasize(f)
|
s := datasize(f)
|
||||||
suffix := map[int]string{16: "W", 32: "L", 64: "Q"}
|
suffix := map[int]string{16: "W", 32: "L", 64: "Q", 128: "X", 256: "Y"}
|
||||||
switch n {
|
switch n {
|
||||||
case "RDRAND", "RDSEED":
|
case "RDRAND", "RDSEED":
|
||||||
n += suffix[s]
|
n += suffix[s]
|
||||||
@@ -150,9 +164,10 @@ func (l Loader) form(f opcodesxml.Form) inst.Form {
|
|||||||
|
|
||||||
// operands maps Opcodes XML operands to avo format.
|
// operands maps Opcodes XML operands to avo format.
|
||||||
func operands(ops []opcodesxml.Operand) []inst.Operand {
|
func operands(ops []opcodesxml.Operand) []inst.Operand {
|
||||||
r := make([]inst.Operand, 0, len(ops))
|
n := len(ops)
|
||||||
for _, op := range ops {
|
r := make([]inst.Operand, len(ops))
|
||||||
r = append(r, operand(op))
|
for i, op := range ops {
|
||||||
|
r[n-1-i] = operand(op)
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
@@ -167,15 +182,30 @@ func operand(op opcodesxml.Operand) inst.Operand {
|
|||||||
|
|
||||||
// datasize (intelligently) guesses the datasize of an instruction form.
|
// datasize (intelligently) guesses the datasize of an instruction form.
|
||||||
func datasize(f opcodesxml.Form) int {
|
func datasize(f opcodesxml.Form) int {
|
||||||
for _, op := range f.Operands {
|
// Determine from encoding bits.
|
||||||
if !op.Output {
|
e := f.Encoding
|
||||||
continue
|
switch {
|
||||||
|
case e.VEX != nil && e.VEX.W == nil:
|
||||||
|
return 128 << e.VEX.L
|
||||||
}
|
}
|
||||||
for s := 8; s <= 64; s *= 2 {
|
|
||||||
|
// Guess from operand types.
|
||||||
|
size := 0
|
||||||
|
for _, op := range f.Operands {
|
||||||
|
s := operandsize(op)
|
||||||
|
if s != 0 && (size == 0 || op.Output) {
|
||||||
|
size = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
func operandsize(op opcodesxml.Operand) int {
|
||||||
|
for s := 8; s <= 256; s *= 2 {
|
||||||
if strings.HasSuffix(op.Type, strconv.Itoa(s)) {
|
if strings.HasSuffix(op.Type, strconv.Itoa(s)) {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
type Alias struct {
|
type Alias struct {
|
||||||
Opcode string
|
Opcode string
|
||||||
DataSize int
|
DataSize int
|
||||||
|
NumOperands int
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildAliasMap constructs a map from AT&T/GNU/Intel to Go syntax.
|
// BuildAliasMap constructs a map from AT&T/GNU/Intel to Go syntax.
|
||||||
@@ -21,9 +22,18 @@ func BuildAliasMap(is []*x86csv.Inst) (map[Alias]string, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.Contains(i.GoOpcode(), "/") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, alt := range []string{i.IntelOpcode(), i.GNUOpcode()} {
|
for _, alt := range []string{i.IntelOpcode(), i.GNUOpcode()} {
|
||||||
if strings.ToUpper(alt) != i.GoOpcode() {
|
if strings.ToUpper(alt) != i.GoOpcode() {
|
||||||
m[Alias{Opcode: strings.ToLower(alt), DataSize: s}] = i.GoOpcode()
|
a := Alias{
|
||||||
|
Opcode: strings.ToLower(alt),
|
||||||
|
DataSize: s,
|
||||||
|
NumOperands: len(i.GoArgs()),
|
||||||
|
}
|
||||||
|
m[a] = i.GoOpcode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ type Encoding struct {
|
|||||||
|
|
||||||
type REX struct {
|
type REX struct {
|
||||||
Mandatory bool `xml:"mandatory,attr"`
|
Mandatory bool `xml:"mandatory,attr"`
|
||||||
W int `xml:"W,attr"`
|
W uint `xml:"W,attr"`
|
||||||
R string `xml:"R,attr"`
|
R string `xml:"R,attr"`
|
||||||
X string `xml:"X,attr"`
|
X string `xml:"X,attr"`
|
||||||
B string `xml:"B,attr"`
|
B string `xml:"B,attr"`
|
||||||
@@ -80,8 +80,8 @@ type REX struct {
|
|||||||
|
|
||||||
type VEX struct {
|
type VEX struct {
|
||||||
Type string `xml:"type,attr"`
|
Type string `xml:"type,attr"`
|
||||||
W int `xml:"W,attr"`
|
W *uint `xml:"W,attr"`
|
||||||
L int `xml:"L,attr"`
|
L uint `xml:"L,attr"`
|
||||||
M5 string `xml:"m-mmmm,attr"`
|
M5 string `xml:"m-mmmm,attr"`
|
||||||
PP string `xml:"pp,attr"`
|
PP string `xml:"pp,attr"`
|
||||||
R string `xml:"R,attr"`
|
R string `xml:"R,attr"`
|
||||||
@@ -93,7 +93,7 @@ type VEX struct {
|
|||||||
type EVEX struct {
|
type EVEX struct {
|
||||||
M2 string `xml:"mm,attr"`
|
M2 string `xml:"mm,attr"`
|
||||||
PP string `xml:"pp,attr"`
|
PP string `xml:"pp,attr"`
|
||||||
W int `xml:"W,attr"`
|
W *uint `xml:"W,attr"`
|
||||||
LL string `xml:"LL,attr"`
|
LL string `xml:"LL,attr"`
|
||||||
V4 string `xml:"vvvv,attr"`
|
V4 string `xml:"vvvv,attr"`
|
||||||
V string `xml:"V,attr"`
|
V string `xml:"V,attr"`
|
||||||
|
|||||||
Reference in New Issue
Block a user