add IsM* operand checks

This commit is contained in:
Michael McLoughlin
2018-11-26 23:35:26 -08:00
parent 3050882621
commit 0ec52ceaa8
2 changed files with 102 additions and 14 deletions

View File

@@ -97,48 +97,79 @@ func IsR64(op avo.Operand) bool {
// IsGP returns true if op is a general-purpose register of size n bytes. // IsGP returns true if op is a general-purpose register of size n bytes.
func IsGP(op avo.Operand, n uint) bool { func IsGP(op avo.Operand, n uint) bool {
r, ok := op.(reg.Register) return IsRegisterKindSize(op, reg.GP, n)
return ok && r.Kind() == reg.GeneralPurpose.Kind && r.Bytes() == n
} }
// IsXmm0 returns true if op is the X0 register.
func IsXmm0(op avo.Operand) bool { func IsXmm0(op avo.Operand) bool {
return false return op == reg.X0
} }
// IsXmm returns true if op is a 128-bit XMM register.
func IsXmm(op avo.Operand) bool { func IsXmm(op avo.Operand) bool {
return false return IsRegisterKindSize(op, reg.SSEAVX, 16)
} }
// IsYmm returns true if op is a 256-bit YMM register.
func IsYmm(op avo.Operand) bool { func IsYmm(op avo.Operand) bool {
return false return IsRegisterKindSize(op, reg.SSEAVX, 32)
} }
// IsRegisterKindSize returns true if op is a register of the given kind and size in bytes.
func IsRegisterKindSize(op avo.Operand, k reg.Kind, n uint) bool {
r, ok := op.(reg.Register)
return ok && r.Kind() == k && r.Bytes() == n
}
// IsM returns true if op is a 16-, 32- or 64-bit memory operand.
func IsM(op avo.Operand) bool { func IsM(op avo.Operand) bool {
return false // TODO(mbm): confirm "m" check is defined correctly
// Intel manual: "A 16-, 32- or 64-bit operand in memory."
return IsM16(op) || IsM32(op) || IsM64(op)
} }
// IsM8 returns true if op is an 8-bit memory operand.
func IsM8(op avo.Operand) bool { func IsM8(op avo.Operand) bool {
return false // TODO(mbm): confirm "m8" check is defined correctly
// Intel manual: "A byte operand in memory, usually expressed as a variable or
// array name, but pointed to by the DS:(E)SI or ES:(E)DI registers. In 64-bit
// mode, it is pointed to by the RSI or RDI registers."
return IsMSize(op, 1)
} }
// IsM16 returns true if op is a 16-bit memory operand.
func IsM16(op avo.Operand) bool { func IsM16(op avo.Operand) bool {
return false return IsMSize(op, 2)
} }
// IsM32 returns true if op is a 16-bit memory operand.
func IsM32(op avo.Operand) bool { func IsM32(op avo.Operand) bool {
return false return IsMSize(op, 4)
} }
// IsM64 returns true if op is a 64-bit memory operand.
func IsM64(op avo.Operand) bool { func IsM64(op avo.Operand) bool {
return false return IsMSize(op, 8)
} }
// IsMSize returns true if op is a memory operand using general-purpose address
// registers of the given size in bytes.
func IsMSize(op avo.Operand, n uint) bool {
// TODO(mbm): should memory operands have a size attribute as well?
m, ok := op.(Mem)
return ok && IsGP(m.Base, n) && (m.Index == nil || IsGP(m.Index, n))
}
// IsM128 returns true if op is a 128-bit memory operand.
func IsM128(op avo.Operand) bool { func IsM128(op avo.Operand) bool {
return false // TODO(mbm): should "m128" be the same as "m64"?
return IsM64(op)
} }
// IsM256 returns true if op is a 256-bit memory operand.
func IsM256(op avo.Operand) bool { func IsM256(op avo.Operand) bool {
return false // TODO(mbm): should "m256" be the same as "m64"?
return IsM64(op)
} }
func IsVm32x(op avo.Operand) bool { func IsVm32x(op avo.Operand) bool {

View File

@@ -5,9 +5,8 @@ import (
"runtime" "runtime"
"testing" "testing"
"github.com/mmcloughlin/avo/reg"
"github.com/mmcloughlin/avo" "github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/reg"
) )
func TestChecks(t *testing.T) { func TestChecks(t *testing.T) {
@@ -19,27 +18,37 @@ func TestChecks(t *testing.T) {
// Immediates // Immediates
{Is1, Imm(1), true}, {Is1, Imm(1), true},
{Is1, Imm(23), false}, {Is1, Imm(23), false},
{Is3, Imm(3), true}, {Is3, Imm(3), true},
{Is3, Imm(23), false}, {Is3, Imm(23), false},
{IsImm2u, Imm(3), true}, {IsImm2u, Imm(3), true},
{IsImm2u, Imm(4), false}, {IsImm2u, Imm(4), false},
{IsImm8, Imm(255), true}, {IsImm8, Imm(255), true},
{IsImm8, Imm(256), false}, {IsImm8, Imm(256), false},
{IsImm16, Imm((1 << 16) - 1), true}, {IsImm16, Imm((1 << 16) - 1), true},
{IsImm16, Imm(1 << 16), false}, {IsImm16, Imm(1 << 16), false},
{IsImm32, Imm((1 << 32) - 1), true}, {IsImm32, Imm((1 << 32) - 1), true},
{IsImm32, Imm(1 << 32), false}, {IsImm32, Imm(1 << 32), false},
{IsImm64, Imm((1 << 64) - 1), true}, {IsImm64, Imm((1 << 64) - 1), true},
// Specific registers // Specific registers
{IsAl, reg.AL, true}, {IsAl, reg.AL, true},
{IsAl, reg.CL, false}, {IsAl, reg.CL, false},
{IsCl, reg.CL, true}, {IsCl, reg.CL, true},
{IsCl, reg.DH, false}, {IsCl, reg.DH, false},
{IsAx, reg.AX, true}, {IsAx, reg.AX, true},
{IsAx, reg.DX, false}, {IsAx, reg.DX, false},
{IsEax, reg.EAX, true}, {IsEax, reg.EAX, true},
{IsEax, reg.ECX, false}, {IsEax, reg.ECX, false},
{IsRax, reg.RAX, true}, {IsRax, reg.RAX, true},
{IsRax, reg.R13, false}, {IsRax, reg.R13, false},
@@ -47,16 +56,64 @@ func TestChecks(t *testing.T) {
{IsR8, reg.AL, true}, {IsR8, reg.AL, true},
{IsR8, reg.CH, true}, {IsR8, reg.CH, true},
{IsR8, reg.EAX, false}, {IsR8, reg.EAX, false},
{IsR16, reg.DX, true}, {IsR16, reg.DX, true},
{IsR16, reg.R10W, true}, {IsR16, reg.R10W, true},
{IsR16, reg.R10B, false}, {IsR16, reg.R10B, false},
{IsR32, reg.EBP, true}, {IsR32, reg.EBP, true},
{IsR32, reg.R14L, true}, {IsR32, reg.R14L, true},
{IsR32, reg.R8, false}, {IsR32, reg.R8, false},
{IsR64, reg.RDX, true}, {IsR64, reg.RDX, true},
{IsR64, reg.R10, true}, {IsR64, reg.R10, true},
{IsR64, reg.EBX, false}, {IsR64, reg.EBX, false},
// SIMD registers
{IsXmm0, reg.X0, true},
{IsXmm0, reg.X13, false},
{IsXmm0, reg.Y3, false},
{IsXmm, reg.X0, true},
{IsXmm, reg.X13, true},
{IsXmm, reg.Y3, false},
{IsXmm, reg.Z23, false},
{IsYmm, reg.Y0, true},
{IsYmm, reg.Y13, true},
{IsYmm, reg.Y31, true},
{IsYmm, reg.X3, false},
{IsYmm, reg.Z3, false},
// Memory operands
{IsM, Mem{Base: reg.CX}, true},
{IsM, Mem{Base: reg.ECX}, true},
{IsM, Mem{Base: reg.RCX}, true},
{IsM, Mem{Base: reg.CL}, false},
{IsM8, Mem{Disp: 8, Base: reg.CL}, true},
{IsM8, Mem{Disp: 8, Base: reg.CL, Index: reg.AH, Scale: 2}, true},
{IsM8, Mem{Disp: 8, Base: reg.AX, Index: reg.AH, Scale: 2}, false},
{IsM8, Mem{Disp: 8, Base: reg.CL, Index: reg.R10, Scale: 2}, false},
{IsM16, Mem{Disp: 4, Base: reg.DX}, true},
{IsM16, Mem{Disp: 4, Base: reg.R13W, Index: reg.R8W, Scale: 2}, true},
{IsM16, Mem{Disp: 4, Base: reg.ESI, Index: reg.R8W, Scale: 2}, false},
{IsM16, Mem{Disp: 4, Base: reg.R13W, Index: reg.R9, Scale: 2}, false},
{IsM32, Mem{Base: reg.R13L, Index: reg.EBX, Scale: 2}, true},
{IsM32, Mem{Base: reg.R13W}, false},
{IsM64, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
{IsM64, Mem{Base: reg.R13L}, false},
{IsM128, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
{IsM128, Mem{Base: reg.R13L}, false},
{IsM256, Mem{Base: reg.RBX, Index: reg.R12, Scale: 2}, true},
{IsM256, Mem{Base: reg.R13L}, false},
} }
for _, c := range cases { for _, c := range cases {
if c.Predicate(c.Operand) != c.Expect { if c.Predicate(c.Operand) != c.Expect {
t.Errorf("%s( %#v ) != %v", funcname(c.Predicate), c.Operand, c.Expect) t.Errorf("%s( %#v ) != %v", funcname(c.Predicate), c.Operand, c.Expect)