blob: e934ed73eb89e480fe6dd90b56fceafe093ad3e2 [file] [log] [blame]
// 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 xeddata
import (
"errors"
"strings"
)
// OperandVisibility describes operand visibility in XED terms.
type OperandVisibility int
const (
// VisExplicit is a default operand visibility.
// Explicit operand is "real" kind of operands that
// is shown in syntax and can be specified by the programmer.
VisExplicit OperandVisibility = iota
// VisImplicit is for fixed arg (like EAX); usually shown in syntax.
VisImplicit
// VisSuppressed is like VisImplicit, but not shown in syntax.
// In some very rare exceptions, they are also shown in syntax string.
VisSuppressed
// VisEcond is encoder-only conditions. Can be ignored.
VisEcond
)
// Operand holds data that is encoded inside
// instruction's "OPERANDS" field.
//
// Use NewOperand function to decode operand fields into Operand object.
type Operand struct {
// Name is an ID with optional nonterminal name part.
//
// Possible values: "REG0=GPRv_B", "REG1", "MEM0", ...
//
// If nonterminal part is present, name
// can be split into LHS and RHS with NonTerminalName method.
Name string
// Action describes argument types.
//
// Possible values: "r", "w", "rw", "cr", "cw", "crw".
// Optional "c" prefix represents conditional access.
Action string
// Width descriptor. It can express simple width like "w" (word, 16bit)
// or meta-width like "v", which corresponds to {16, 32, 64} bits.
//
// Possible values: "", "q", "ds", "dq", ...
// Optional.
Width string
// Xtype holds XED-specific type information.
//
// Possible values: "", "f64", "i32", ...
// Optional.
Xtype string
// Attributes serves as container for all other properties.
//
// Possible values:
// EVEX.b context {
// TXT=ZEROSTR - zeroing
// TXT=SAESTR - surpress all exceptions
// TXT=ROUNDC - rounding
// TXT=BCASTSTR - broadcasting
// }
// MULTISOURCE4 - 4FMA multi-register operand.
//
// Optional. For most operands, it's nil.
Attributes map[string]bool
// Visibility tells if operand is explicit, implicit or suspended.
Visibility OperandVisibility
}
var xedVisibilities = map[string]OperandVisibility{
"EXPL": VisExplicit,
"IMPL": VisImplicit,
"SUPP": VisSuppressed,
"ECOND": VisEcond,
}
// NewOperand decodes operand string.
//
// See "$XED/pysrc/opnds.py" to learn about fields format
// and valid combinations.
//
// Requires database with xtypes and widths info.
func NewOperand(db *Database, s string) (*Operand, error) {
if db.widths == nil {
return nil, errors.New("Database.widths is nil")
}
fields := strings.Split(s, ":")
switch len(fields) {
case 0:
return nil, errors.New("empty operand fields string")
case 1:
return &Operand{Name: fields[0]}, nil
}
var op Operand
// First two fields are fixed.
op.Name = fields[0]
op.Action = fields[1]
// Optional fields.
for _, f := range fields[2:] {
if db.widths[f] != nil && op.Width == "" {
op.Width = f
} else if vis, ok := xedVisibilities[f]; ok {
op.Visibility = vis
} else if xtype := db.xtypes[f]; xtype != nil {
op.Xtype = f
} else {
if op.Attributes == nil {
op.Attributes = make(map[string]bool)
}
op.Attributes[f] = true
}
}
return &op, nil
}
// NonterminalName returns true if op.Name consist
// of LHS and RHS parts.
//
// RHS is non-terminal name lookup function expression.
// Example: "REG0=GPRv()" has "GPRv()" name lookup function.
func (op *Operand) NonterminalName() bool {
return strings.Contains(op.Name, "=")
}
// NameLHS returns left hand side part of the non-terminal name.
// Example: NameLHS("REG0=GPRv()") => "REG0".
func (op *Operand) NameLHS() string {
return strings.Split(op.Name, "=")[0]
}
// NameRHS returns right hand side part of the non-terminal name.
// Example: NameLHS("REG0=GPRv()") => "GPRv()".
func (op *Operand) NameRHS() string {
return strings.Split(op.Name, "=")[1]
}
// IsVisible returns true for operands that are usually
// shown in syntax strings.
func (op *Operand) IsVisible() bool {
return op.Visibility == VisExplicit ||
op.Visibility == VisImplicit
}