From 0ec52ceaa8c6e46c69ee621c165d7a229bb3a68c Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 26 Nov 2018 23:35:26 -0800 Subject: [PATCH] add IsM* operand checks --- operand/checks.go | 55 ++++++++++++++++++++++++++++--------- operand/checks_test.go | 61 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 14 deletions(-) diff --git a/operand/checks.go b/operand/checks.go index 1186c38..72e5c96 100644 --- a/operand/checks.go +++ b/operand/checks.go @@ -97,48 +97,79 @@ func IsR64(op avo.Operand) bool { // IsGP returns true if op is a general-purpose register of size n bytes. func IsGP(op avo.Operand, n uint) bool { - r, ok := op.(reg.Register) - return ok && r.Kind() == reg.GeneralPurpose.Kind && r.Bytes() == n + return IsRegisterKindSize(op, reg.GP, n) } +// IsXmm0 returns true if op is the X0 register. 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 { - 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 { - 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 { - 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 { - 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 { - return false + return IsMSize(op, 2) } +// IsM32 returns true if op is a 16-bit memory operand. 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 { - 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 { - 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 { - return false + // TODO(mbm): should "m256" be the same as "m64"? + return IsM64(op) } func IsVm32x(op avo.Operand) bool { diff --git a/operand/checks_test.go b/operand/checks_test.go index cbd6068..b9140d8 100644 --- a/operand/checks_test.go +++ b/operand/checks_test.go @@ -5,9 +5,8 @@ import ( "runtime" "testing" - "github.com/mmcloughlin/avo/reg" - "github.com/mmcloughlin/avo" + "github.com/mmcloughlin/avo/reg" ) func TestChecks(t *testing.T) { @@ -19,27 +18,37 @@ func TestChecks(t *testing.T) { // Immediates {Is1, Imm(1), true}, {Is1, Imm(23), false}, + {Is3, Imm(3), true}, {Is3, Imm(23), false}, + {IsImm2u, Imm(3), true}, {IsImm2u, Imm(4), false}, + {IsImm8, Imm(255), true}, {IsImm8, Imm(256), false}, + {IsImm16, Imm((1 << 16) - 1), true}, {IsImm16, Imm(1 << 16), false}, + {IsImm32, Imm((1 << 32) - 1), true}, {IsImm32, Imm(1 << 32), false}, + {IsImm64, Imm((1 << 64) - 1), true}, // Specific registers {IsAl, reg.AL, true}, {IsAl, reg.CL, false}, + {IsCl, reg.CL, true}, {IsCl, reg.DH, false}, + {IsAx, reg.AX, true}, {IsAx, reg.DX, false}, + {IsEax, reg.EAX, true}, {IsEax, reg.ECX, false}, + {IsRax, reg.RAX, true}, {IsRax, reg.R13, false}, @@ -47,16 +56,64 @@ func TestChecks(t *testing.T) { {IsR8, reg.AL, true}, {IsR8, reg.CH, true}, {IsR8, reg.EAX, false}, + {IsR16, reg.DX, true}, {IsR16, reg.R10W, true}, {IsR16, reg.R10B, false}, + {IsR32, reg.EBP, true}, {IsR32, reg.R14L, true}, {IsR32, reg.R8, false}, + {IsR64, reg.RDX, true}, {IsR64, reg.R10, true}, {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 { if c.Predicate(c.Operand) != c.Expect { t.Errorf("%s( %#v ) != %v", funcname(c.Predicate), c.Operand, c.Expect)