Files
avo/internal/inst/types.go
Michael McLoughlin d43efabdbe inst,ir: cancelling inputs (#92)
Adds support for a `CancellingInputs` instruction flag, to indicate cases like `XORQ R10, R10` where the instruction actually does not depend on the value of `R10` at all.

Closes #89
2019-07-28 17:58:49 -07:00

171 lines
4.0 KiB
Go

package inst
import (
"sort"
"strings"
)
// Instruction represents an x86 instruction.
type Instruction struct {
Opcode string // Golang assembly mnemonic
AliasOf string // Opcode of instruction that this is an alias for
Summary string // Description of the instruction
Forms []Form // Accepted operand forms
}
// IsTerminal reports whether the instruction exits a function.
func (i Instruction) IsTerminal() bool {
// TODO(mbm): how about the RETF* instructions
return i.Opcode == "RET"
}
// IsBranch reports whether the instruction is a branch; that is, if it can
// cause control flow to jump to another location.
func (i Instruction) IsBranch() bool {
if i.Opcode == "CALL" {
return false
}
for _, f := range i.Forms {
for _, op := range f.Operands {
if strings.HasPrefix(op.Type, "rel") {
return true
}
}
}
return false
}
// IsConditionalBranch reports whether the instruction branches dependent on some condition.
func (i Instruction) IsConditionalBranch() bool {
return i.IsBranch() && i.Opcode != "JMP"
}
// Arities returns the unique arities among the instruction forms.
func (i Instruction) Arities() []int {
s := map[int]bool{}
for _, f := range i.Forms {
s[f.Arity()] = true
}
a := make([]int, 0, len(s))
for n := range s {
a = append(a, n)
}
sort.Ints(a)
return a
}
// Arity is a convenience for returning the unique instruction arity when you
// know it is not variadic. Panics for a variadic instruction.
func (i Instruction) Arity() int {
if i.IsVariadic() {
panic("variadic")
}
a := i.Arities()
return a[0]
}
// IsVariadic reports whether the instruction has more than one arity.
func (i Instruction) IsVariadic() bool {
return len(i.Arities()) > 1
}
// IsNiladic reports whether the instruction takes no operands.
func (i Instruction) IsNiladic() bool {
a := i.Arities()
return len(a) == 1 && a[0] == 0
}
// Form specifies one accepted set of operands for an instruction.
type Form struct {
// Instruction sets this instruction form requires.
ISA []string
// Operands required for this form.
Operands []Operand
// Registers read or written but not explicitly passed to the instruction.
ImplicitOperands []ImplicitOperand
// CancellingInputs indicates this instruction form has no dependency on the
// input operands when they refer to the same register. The classic example of
// this is "XORQ RAX, RAX", in which case the output has no dependence on the
// value of RAX. Instruction forms with cancelling inputs have only two input
// operands, which have the same register type.
CancellingInputs bool
}
// Arity returns the number of operands this form expects.
func (f Form) Arity() int {
return len(f.Operands)
}
// Signature returns the list of operand types.
func (f Form) Signature() []string {
s := make([]string, f.Arity())
for i, op := range f.Operands {
s[i] = op.Type
}
return s
}
// Operand is an operand to an instruction, describing the expected type and read/write action.
type Operand struct {
Type string
Action Action
}
// ImplicitOperand describes a register that is implicitly read/written by an instruction.
type ImplicitOperand struct {
Register string
Action Action
}
// Action specifies the read/write operation of an instruction on an operand.
type Action uint8
// Possible Action types.
const (
R Action = 0x1
W Action = 0x2
RW Action = R | W
)
// ActionFromReadWrite builds an Action from boolean flags.
func ActionFromReadWrite(r, w bool) Action {
var a Action
if r {
a |= R
}
if w {
a |= W
}
return a
}
// Contains reports whether a supports all actions in s.
func (a Action) Contains(s Action) bool {
return (a & s) == s
}
// Read reports whether a supports read.
func (a Action) Read() bool {
return a.Contains(R)
}
// Write reports whether a supports write.
func (a Action) Write() bool {
return a.Contains(W)
}
// String represents a as a human-readable string.
func (a Action) String() string {
s := ""
if a.Read() {
s += "r"
}
if a.Write() {
s += "w"
}
return s
}