1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
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
}
|