start to implement operand types and checks
This commit is contained in:
@@ -1,71 +1,104 @@
|
|||||||
package operand
|
package operand
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/mmcloughlin/avo/reg"
|
||||||
|
|
||||||
"github.com/mmcloughlin/avo"
|
"github.com/mmcloughlin/avo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Is1 returns true if op is the immediate constant 1.
|
||||||
func Is1(op avo.Operand) bool {
|
func Is1(op avo.Operand) bool {
|
||||||
return false
|
i, ok := op.(Imm)
|
||||||
|
return ok && i == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is3 returns true if op is the immediate constant 3.
|
||||||
func Is3(op avo.Operand) bool {
|
func Is3(op avo.Operand) bool {
|
||||||
return false
|
i, ok := op.(Imm)
|
||||||
|
return ok && i == 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsImm2u returns true if op is a 2-bit unsigned immediate (less than 4).
|
||||||
func IsImm2u(op avo.Operand) bool {
|
func IsImm2u(op avo.Operand) bool {
|
||||||
return false
|
i, ok := op.(Imm)
|
||||||
|
return ok && i < 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsImm8 returns true is op is an 8-bit immediate.
|
||||||
func IsImm8(op avo.Operand) bool {
|
func IsImm8(op avo.Operand) bool {
|
||||||
return false
|
i, ok := op.(Imm)
|
||||||
|
return ok && i <= math.MaxUint8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsImm16 returns true is op is a 16-bit immediate.
|
||||||
func IsImm16(op avo.Operand) bool {
|
func IsImm16(op avo.Operand) bool {
|
||||||
return false
|
i, ok := op.(Imm)
|
||||||
|
return ok && i <= math.MaxUint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsImm32 returns true is op is a 32-bit immediate.
|
||||||
func IsImm32(op avo.Operand) bool {
|
func IsImm32(op avo.Operand) bool {
|
||||||
return false
|
i, ok := op.(Imm)
|
||||||
|
return ok && i <= math.MaxUint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsImm64 returns true is op is a 64-bit immediate.
|
||||||
func IsImm64(op avo.Operand) bool {
|
func IsImm64(op avo.Operand) bool {
|
||||||
return false
|
_, ok := op.(Imm)
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsAl returns true if op is the AL register.
|
||||||
func IsAl(op avo.Operand) bool {
|
func IsAl(op avo.Operand) bool {
|
||||||
return false
|
return op == reg.AL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsCl returns true if op is the CL register.
|
||||||
func IsCl(op avo.Operand) bool {
|
func IsCl(op avo.Operand) bool {
|
||||||
return false
|
return op == reg.CL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsAx returns true if op is the 16-bit AX register.
|
||||||
func IsAx(op avo.Operand) bool {
|
func IsAx(op avo.Operand) bool {
|
||||||
return false
|
return op == reg.AX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsEax returns true if op is the 32-bit EAX register.
|
||||||
func IsEax(op avo.Operand) bool {
|
func IsEax(op avo.Operand) bool {
|
||||||
return false
|
return op == reg.EAX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsRax returns true if op is the 64-bit RAX register.
|
||||||
func IsRax(op avo.Operand) bool {
|
func IsRax(op avo.Operand) bool {
|
||||||
return false
|
return op == reg.RAX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsR8 returns true if op is an 8-bit general-purpose register.
|
||||||
func IsR8(op avo.Operand) bool {
|
func IsR8(op avo.Operand) bool {
|
||||||
return false
|
return IsGP(op, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsR16 returns true if op is a 16-bit general-purpose register.
|
||||||
func IsR16(op avo.Operand) bool {
|
func IsR16(op avo.Operand) bool {
|
||||||
return false
|
return IsGP(op, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsR32 returns true if op is a 32-bit general-purpose register.
|
||||||
func IsR32(op avo.Operand) bool {
|
func IsR32(op avo.Operand) bool {
|
||||||
return false
|
return IsGP(op, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsR64 returns true if op is a 64-bit general-purpose register.
|
||||||
func IsR64(op avo.Operand) bool {
|
func IsR64(op avo.Operand) bool {
|
||||||
return false
|
return IsGP(op, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsXmm0(op avo.Operand) bool {
|
func IsXmm0(op avo.Operand) bool {
|
||||||
|
|||||||
69
operand/checks_test.go
Normal file
69
operand/checks_test.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package operand
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mmcloughlin/avo/reg"
|
||||||
|
|
||||||
|
"github.com/mmcloughlin/avo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChecks(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Predicate func(avo.Operand) bool
|
||||||
|
Operand avo.Operand
|
||||||
|
Expect bool
|
||||||
|
}{
|
||||||
|
// 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},
|
||||||
|
|
||||||
|
// General-purpose registers
|
||||||
|
{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},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
if c.Predicate(c.Operand) != c.Expect {
|
||||||
|
t.Errorf("%s( %#v ) != %v", funcname(c.Predicate), c.Operand, c.Expect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func funcname(f interface{}) string {
|
||||||
|
return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
|
||||||
|
}
|
||||||
34
operand/types.go
Normal file
34
operand/types.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package operand
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/mmcloughlin/avo/reg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mem struct {
|
||||||
|
Disp int
|
||||||
|
Base reg.Register
|
||||||
|
Index reg.Register
|
||||||
|
Scale uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Mem) Asm() string {
|
||||||
|
a := ""
|
||||||
|
if m.Disp != 0 {
|
||||||
|
a += fmt.Sprintf("%d", m.Disp)
|
||||||
|
}
|
||||||
|
if m.Base != nil {
|
||||||
|
a += fmt.Sprintf("(%s)", m.Base.Asm())
|
||||||
|
}
|
||||||
|
if m.Index != nil && m.Scale != 0 {
|
||||||
|
a += fmt.Sprintf("(%s*%d)", m.Index.Asm(), m.Scale)
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
type Imm uint64
|
||||||
|
|
||||||
|
func (i Imm) Asm() string {
|
||||||
|
return fmt.Sprintf("%#x", uint64(i))
|
||||||
|
}
|
||||||
28
operand/types_test.go
Normal file
28
operand/types_test.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package operand
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mmcloughlin/avo/reg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMemAsm(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Mem Mem
|
||||||
|
Expect string
|
||||||
|
}{
|
||||||
|
{Mem{Base: reg.EAX}, "(AX)"},
|
||||||
|
{Mem{Disp: 16, Base: reg.RAX}, "16(AX)"},
|
||||||
|
{Mem{Base: reg.R11, Index: reg.RAX, Scale: 4}, "(R11)(AX*4)"},
|
||||||
|
{Mem{Base: reg.R11, Index: reg.RAX, Scale: 1}, "(R11)(AX*1)"},
|
||||||
|
{Mem{Base: reg.R11, Index: reg.RAX}, "(R11)"},
|
||||||
|
{Mem{Base: reg.R11, Scale: 8}, "(R11)"},
|
||||||
|
{Mem{Disp: 2048, Base: reg.R11, Index: reg.RAX, Scale: 8}, "2048(R11)(AX*8)"},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
got := c.Mem.Asm()
|
||||||
|
if got != c.Expect {
|
||||||
|
t.Errorf("%#v.Asm() = %s expected %s", c.Mem, got, c.Expect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user