1package operand 2 3import "github.com/mmcloughlin/avo/reg" 4 5// Pure type assertion checks: 6 7// IsRegister returns whether op has type reg.Register. 8func IsRegister(op Op) bool { _, ok := op.(reg.Register); return ok } 9 10// IsMem returns whether op has type Mem. 11func IsMem(op Op) bool { _, ok := op.(Mem); return ok } 12 13// IsRel returns whether op has type Rel. 14func IsRel(op Op) bool { _, ok := op.(Rel); return ok } 15 16// Checks corresponding to specific operand types in the Intel Manual: 17 18// Is1 returns true if op is the immediate constant 1. 19func Is1(op Op) bool { 20 i, ok := op.(U8) 21 return ok && i == 1 22} 23 24// Is3 returns true if op is the immediate constant 3. 25func Is3(op Op) bool { 26 i, ok := op.(U8) 27 return ok && i == 3 28} 29 30// IsIMM2U returns true if op is a 2-bit unsigned immediate (less than 4). 31func IsIMM2U(op Op) bool { 32 i, ok := op.(U8) 33 return ok && i < 4 34} 35 36// IsIMM8 returns true is op is an 8-bit immediate. 37func IsIMM8(op Op) bool { 38 _, ok := op.(U8) 39 return ok 40} 41 42// IsIMM16 returns true is op is a 16-bit immediate. 43func IsIMM16(op Op) bool { 44 _, ok := op.(U16) 45 return ok 46} 47 48// IsIMM32 returns true is op is a 32-bit immediate. 49func IsIMM32(op Op) bool { 50 _, ok := op.(U32) 51 return ok 52} 53 54// IsIMM64 returns true is op is a 64-bit immediate. 55func IsIMM64(op Op) bool { 56 _, ok := op.(U64) 57 return ok 58} 59 60// IsAL returns true if op is the AL register. 61func IsAL(op Op) bool { 62 return op == reg.AL 63} 64 65// IsCL returns true if op is the CL register. 66func IsCL(op Op) bool { 67 return op == reg.CL 68} 69 70// IsAX returns true if op is the 16-bit AX register. 71func IsAX(op Op) bool { 72 return op == reg.AX 73} 74 75// IsEAX returns true if op is the 32-bit EAX register. 76func IsEAX(op Op) bool { 77 return op == reg.EAX 78} 79 80// IsRAX returns true if op is the 64-bit RAX register. 81func IsRAX(op Op) bool { 82 return op == reg.RAX 83} 84 85// IsR8 returns true if op is an 8-bit general-purpose register. 86func IsR8(op Op) bool { 87 return IsGP(op, 1) 88} 89 90// IsR16 returns true if op is a 16-bit general-purpose register. 91func IsR16(op Op) bool { 92 return IsGP(op, 2) 93} 94 95// IsR32 returns true if op is a 32-bit general-purpose register. 96func IsR32(op Op) bool { 97 return IsGP(op, 4) 98} 99 100// IsR64 returns true if op is a 64-bit general-purpose register. 101func IsR64(op Op) bool { 102 return IsGP(op, 8) 103} 104 105// IsPseudo returns true if op is a pseudo register. 106func IsPseudo(op Op) bool { 107 return IsRegisterKind(op, reg.KindPseudo) 108} 109 110// IsGP returns true if op is a general-purpose register of size n bytes. 111func IsGP(op Op, n uint) bool { 112 return IsRegisterKindSize(op, reg.KindGP, n) 113} 114 115// IsXMM0 returns true if op is the X0 register. 116func IsXMM0(op Op) bool { 117 return op == reg.X0 118} 119 120// IsXMM returns true if op is a 128-bit XMM register. 121func IsXMM(op Op) bool { 122 return IsRegisterKindSize(op, reg.KindVector, 16) 123} 124 125// IsYMM returns true if op is a 256-bit YMM register. 126func IsYMM(op Op) bool { 127 return IsRegisterKindSize(op, reg.KindVector, 32) 128} 129 130// IsRegisterKindSize returns true if op is a register of the given kind and size in bytes. 131func IsRegisterKindSize(op Op, k reg.Kind, n uint) bool { 132 r, ok := op.(reg.Register) 133 return ok && r.Kind() == k && r.Size() == n 134} 135 136// IsRegisterKind returns true if op is a register of the given kind. 137func IsRegisterKind(op Op, k reg.Kind) bool { 138 r, ok := op.(reg.Register) 139 return ok && r.Kind() == k 140} 141 142// IsM returns true if op is a 16-, 32- or 64-bit memory operand. 143func IsM(op Op) bool { 144 // TODO(mbm): confirm "m" check is defined correctly 145 // Intel manual: "A 16-, 32- or 64-bit operand in memory." 146 return IsM16(op) || IsM32(op) || IsM64(op) 147} 148 149// IsM8 returns true if op is an 8-bit memory operand. 150func IsM8(op Op) bool { 151 // TODO(mbm): confirm "m8" check is defined correctly 152 // Intel manual: "A byte operand in memory, usually expressed as a variable or 153 // array name, but pointed to by the DS:(E)SI or ES:(E)DI registers. In 64-bit 154 // mode, it is pointed to by the RSI or RDI registers." 155 return IsMSize(op, 1) 156} 157 158// IsM16 returns true if op is a 16-bit memory operand. 159func IsM16(op Op) bool { 160 return IsMSize(op, 2) 161} 162 163// IsM32 returns true if op is a 16-bit memory operand. 164func IsM32(op Op) bool { 165 return IsMSize(op, 4) 166} 167 168// IsM64 returns true if op is a 64-bit memory operand. 169func IsM64(op Op) bool { 170 return IsMSize(op, 8) 171} 172 173// IsMSize returns true if op is a memory operand using general-purpose address 174// registers of the given size in bytes. 175func IsMSize(op Op, n uint) bool { 176 // TODO(mbm): should memory operands have a size attribute as well? 177 // TODO(mbm): m8,m16,m32,m64 checks do not actually check size 178 m, ok := op.(Mem) 179 return ok && IsMReg(m.Base) && (m.Index == nil || IsMReg(m.Index)) 180} 181 182// IsMReg returns true if op is a register that can be used in a memory operand. 183func IsMReg(op Op) bool { 184 return IsPseudo(op) || IsRegisterKind(op, reg.KindGP) 185} 186 187// IsM128 returns true if op is a 128-bit memory operand. 188func IsM128(op Op) bool { 189 // TODO(mbm): should "m128" be the same as "m64"? 190 return IsM64(op) 191} 192 193// IsM256 returns true if op is a 256-bit memory operand. 194func IsM256(op Op) bool { 195 // TODO(mbm): should "m256" be the same as "m64"? 196 return IsM64(op) 197} 198 199// IsVM32X returns true if op is a vector memory operand with 32-bit XMM index. 200func IsVM32X(op Op) bool { 201 return IsVmx(op) 202} 203 204// IsVM64X returns true if op is a vector memory operand with 64-bit XMM index. 205func IsVM64X(op Op) bool { 206 return IsVmx(op) 207} 208 209// IsVmx returns true if op is a vector memory operand with XMM index. 210func IsVmx(op Op) bool { 211 return isvm(op, IsXMM) 212} 213 214// IsVM32Y returns true if op is a vector memory operand with 32-bit YMM index. 215func IsVM32Y(op Op) bool { 216 return IsVmy(op) 217} 218 219// IsVM64Y returns true if op is a vector memory operand with 64-bit YMM index. 220func IsVM64Y(op Op) bool { 221 return IsVmy(op) 222} 223 224// IsVmy returns true if op is a vector memory operand with YMM index. 225func IsVmy(op Op) bool { 226 return isvm(op, IsYMM) 227} 228 229func isvm(op Op, idx func(Op) bool) bool { 230 m, ok := op.(Mem) 231 return ok && IsR64(m.Base) && idx(m.Index) 232} 233 234// IsREL8 returns true if op is an 8-bit offset relative to instruction pointer. 235func IsREL8(op Op) bool { 236 r, ok := op.(Rel) 237 return ok && r == Rel(int8(r)) 238} 239 240// IsREL32 returns true if op is an offset relative to instruction pointer, or a 241// label reference. 242func IsREL32(op Op) bool { 243 // TODO(mbm): should labels be considered separately? 244 _, rel := op.(Rel) 245 _, label := op.(LabelRef) 246 return rel || label 247} 248