summaryrefslogtreecommitdiff
path: root/vendor/github.com/mmcloughlin/avo/operand
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mmcloughlin/avo/operand')
-rw-r--r--vendor/github.com/mmcloughlin/avo/operand/checks.go247
-rw-r--r--vendor/github.com/mmcloughlin/avo/operand/const.go36
-rw-r--r--vendor/github.com/mmcloughlin/avo/operand/doc.go2
-rw-r--r--vendor/github.com/mmcloughlin/avo/operand/types.go151
-rw-r--r--vendor/github.com/mmcloughlin/avo/operand/zconst.go75
5 files changed, 511 insertions, 0 deletions
diff --git a/vendor/github.com/mmcloughlin/avo/operand/checks.go b/vendor/github.com/mmcloughlin/avo/operand/checks.go
new file mode 100644
index 0000000..2585479
--- /dev/null
+++ b/vendor/github.com/mmcloughlin/avo/operand/checks.go
@@ -0,0 +1,247 @@
+package operand
+
+import "github.com/mmcloughlin/avo/reg"
+
+// Pure type assertion checks:
+
+// IsRegister returns whether op has type reg.Register.
+func IsRegister(op Op) bool { _, ok := op.(reg.Register); return ok }
+
+// IsMem returns whether op has type Mem.
+func IsMem(op Op) bool { _, ok := op.(Mem); return ok }
+
+// IsRel returns whether op has type Rel.
+func IsRel(op Op) bool { _, ok := op.(Rel); return ok }
+
+// Checks corresponding to specific operand types in the Intel Manual:
+
+// Is1 returns true if op is the immediate constant 1.
+func Is1(op Op) bool {
+ i, ok := op.(U8)
+ return ok && i == 1
+}
+
+// Is3 returns true if op is the immediate constant 3.
+func Is3(op Op) bool {
+ i, ok := op.(U8)
+ return ok && i == 3
+}
+
+// IsIMM2U returns true if op is a 2-bit unsigned immediate (less than 4).
+func IsIMM2U(op Op) bool {
+ i, ok := op.(U8)
+ return ok && i < 4
+}
+
+// IsIMM8 returns true is op is an 8-bit immediate.
+func IsIMM8(op Op) bool {
+ _, ok := op.(U8)
+ return ok
+}
+
+// IsIMM16 returns true is op is a 16-bit immediate.
+func IsIMM16(op Op) bool {
+ _, ok := op.(U16)
+ return ok
+}
+
+// IsIMM32 returns true is op is a 32-bit immediate.
+func IsIMM32(op Op) bool {
+ _, ok := op.(U32)
+ return ok
+}
+
+// IsIMM64 returns true is op is a 64-bit immediate.
+func IsIMM64(op Op) bool {
+ _, ok := op.(U64)
+ return ok
+}
+
+// IsAL returns true if op is the AL register.
+func IsAL(op Op) bool {
+ return op == reg.AL
+}
+
+// IsCL returns true if op is the CL register.
+func IsCL(op Op) bool {
+ return op == reg.CL
+}
+
+// IsAX returns true if op is the 16-bit AX register.
+func IsAX(op Op) bool {
+ return op == reg.AX
+}
+
+// IsEAX returns true if op is the 32-bit EAX register.
+func IsEAX(op Op) bool {
+ return op == reg.EAX
+}
+
+// IsRAX returns true if op is the 64-bit RAX register.
+func IsRAX(op Op) bool {
+ return op == reg.RAX
+}
+
+// IsR8 returns true if op is an 8-bit general-purpose register.
+func IsR8(op Op) bool {
+ return IsGP(op, 1)
+}
+
+// IsR16 returns true if op is a 16-bit general-purpose register.
+func IsR16(op Op) bool {
+ return IsGP(op, 2)
+}
+
+// IsR32 returns true if op is a 32-bit general-purpose register.
+func IsR32(op Op) bool {
+ return IsGP(op, 4)
+}
+
+// IsR64 returns true if op is a 64-bit general-purpose register.
+func IsR64(op Op) bool {
+ return IsGP(op, 8)
+}
+
+// IsPseudo returns true if op is a pseudo register.
+func IsPseudo(op Op) bool {
+ return IsRegisterKind(op, reg.KindPseudo)
+}
+
+// IsGP returns true if op is a general-purpose register of size n bytes.
+func IsGP(op Op, n uint) bool {
+ return IsRegisterKindSize(op, reg.KindGP, n)
+}
+
+// IsXMM0 returns true if op is the X0 register.
+func IsXMM0(op Op) bool {
+ return op == reg.X0
+}
+
+// IsXMM returns true if op is a 128-bit XMM register.
+func IsXMM(op Op) bool {
+ return IsRegisterKindSize(op, reg.KindVector, 16)
+}
+
+// IsYMM returns true if op is a 256-bit YMM register.
+func IsYMM(op Op) bool {
+ return IsRegisterKindSize(op, reg.KindVector, 32)
+}
+
+// IsRegisterKindSize returns true if op is a register of the given kind and size in bytes.
+func IsRegisterKindSize(op Op, k reg.Kind, n uint) bool {
+ r, ok := op.(reg.Register)
+ return ok && r.Kind() == k && r.Size() == n
+}
+
+// IsRegisterKind returns true if op is a register of the given kind.
+func IsRegisterKind(op Op, k reg.Kind) bool {
+ r, ok := op.(reg.Register)
+ return ok && r.Kind() == k
+}
+
+// IsM returns true if op is a 16-, 32- or 64-bit memory operand.
+func IsM(op Op) bool {
+ // 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 Op) bool {
+ // 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 Op) bool {
+ return IsMSize(op, 2)
+}
+
+// IsM32 returns true if op is a 16-bit memory operand.
+func IsM32(op Op) bool {
+ return IsMSize(op, 4)
+}
+
+// IsM64 returns true if op is a 64-bit memory operand.
+func IsM64(op Op) bool {
+ 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 Op, n uint) bool {
+ // TODO(mbm): should memory operands have a size attribute as well?
+ // TODO(mbm): m8,m16,m32,m64 checks do not actually check size
+ m, ok := op.(Mem)
+ return ok && IsMReg(m.Base) && (m.Index == nil || IsMReg(m.Index))
+}
+
+// IsMReg returns true if op is a register that can be used in a memory operand.
+func IsMReg(op Op) bool {
+ return IsPseudo(op) || IsRegisterKind(op, reg.KindGP)
+}
+
+// IsM128 returns true if op is a 128-bit memory operand.
+func IsM128(op Op) bool {
+ // 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 Op) bool {
+ // TODO(mbm): should "m256" be the same as "m64"?
+ return IsM64(op)
+}
+
+// IsVM32X returns true if op is a vector memory operand with 32-bit XMM index.
+func IsVM32X(op Op) bool {
+ return IsVmx(op)
+}
+
+// IsVM64X returns true if op is a vector memory operand with 64-bit XMM index.
+func IsVM64X(op Op) bool {
+ return IsVmx(op)
+}
+
+// IsVmx returns true if op is a vector memory operand with XMM index.
+func IsVmx(op Op) bool {
+ return isvm(op, IsXMM)
+}
+
+// IsVM32Y returns true if op is a vector memory operand with 32-bit YMM index.
+func IsVM32Y(op Op) bool {
+ return IsVmy(op)
+}
+
+// IsVM64Y returns true if op is a vector memory operand with 64-bit YMM index.
+func IsVM64Y(op Op) bool {
+ return IsVmy(op)
+}
+
+// IsVmy returns true if op is a vector memory operand with YMM index.
+func IsVmy(op Op) bool {
+ return isvm(op, IsYMM)
+}
+
+func isvm(op Op, idx func(Op) bool) bool {
+ m, ok := op.(Mem)
+ return ok && IsR64(m.Base) && idx(m.Index)
+}
+
+// IsREL8 returns true if op is an 8-bit offset relative to instruction pointer.
+func IsREL8(op Op) bool {
+ r, ok := op.(Rel)
+ return ok && r == Rel(int8(r))
+}
+
+// IsREL32 returns true if op is an offset relative to instruction pointer, or a
+// label reference.
+func IsREL32(op Op) bool {
+ // TODO(mbm): should labels be considered separately?
+ _, rel := op.(Rel)
+ _, label := op.(LabelRef)
+ return rel || label
+}
diff --git a/vendor/github.com/mmcloughlin/avo/operand/const.go b/vendor/github.com/mmcloughlin/avo/operand/const.go
new file mode 100644
index 0000000..b2c6a6f
--- /dev/null
+++ b/vendor/github.com/mmcloughlin/avo/operand/const.go
@@ -0,0 +1,36 @@
+package operand
+
+import "fmt"
+
+// Constant represents a constant literal.
+type Constant interface {
+ Op
+ Bytes() int
+ constant()
+}
+
+//go:generate go run make_const.go -output zconst.go
+
+// String is a string constant.
+type String string
+
+// Asm returns an assembly syntax representation of the string s.
+func (s String) Asm() string { return fmt.Sprintf("$%q", s) }
+
+// Bytes returns the length of s.
+func (s String) Bytes() int { return len(s) }
+
+func (s String) constant() {}
+
+// Imm returns an unsigned integer constant with size guessed from x.
+func Imm(x uint64) Constant {
+ switch {
+ case uint64(uint8(x)) == x:
+ return U8(x)
+ case uint64(uint16(x)) == x:
+ return U16(x)
+ case uint64(uint32(x)) == x:
+ return U32(x)
+ }
+ return U64(x)
+}
diff --git a/vendor/github.com/mmcloughlin/avo/operand/doc.go b/vendor/github.com/mmcloughlin/avo/operand/doc.go
new file mode 100644
index 0000000..51c44df
--- /dev/null
+++ b/vendor/github.com/mmcloughlin/avo/operand/doc.go
@@ -0,0 +1,2 @@
+// Package operand provides types for instruction operands.
+package operand
diff --git a/vendor/github.com/mmcloughlin/avo/operand/types.go b/vendor/github.com/mmcloughlin/avo/operand/types.go
new file mode 100644
index 0000000..878425e
--- /dev/null
+++ b/vendor/github.com/mmcloughlin/avo/operand/types.go
@@ -0,0 +1,151 @@
+package operand
+
+import (
+ "fmt"
+
+ "github.com/mmcloughlin/avo/reg"
+)
+
+// Op is an operand.
+type Op interface {
+ Asm() string
+}
+
+// Symbol represents a symbol name.
+type Symbol struct {
+ Name string
+ Static bool // only visible in current source file
+}
+
+// NewStaticSymbol builds a static Symbol. Static symbols are only visible in the current source file.
+func NewStaticSymbol(name string) Symbol {
+ return Symbol{Name: name, Static: true}
+}
+
+func (s Symbol) String() string {
+ n := s.Name
+ if s.Static {
+ n += "<>"
+ }
+ return n
+}
+
+// Mem represents a memory reference.
+type Mem struct {
+ Symbol Symbol
+ Disp int
+ Base reg.Register
+ Index reg.Register
+ Scale uint8
+}
+
+// NewParamAddr is a convenience to build a Mem operand pointing to a function
+// parameter, which is a named offset from the frame pointer pseudo register.
+func NewParamAddr(name string, offset int) Mem {
+ return Mem{
+ Symbol: Symbol{
+ Name: name,
+ Static: false,
+ },
+ Disp: offset,
+ Base: reg.FramePointer,
+ }
+}
+
+// NewStackAddr returns a memory reference relative to the stack pointer.
+func NewStackAddr(offset int) Mem {
+ return Mem{
+ Disp: offset,
+ Base: reg.StackPointer,
+ }
+}
+
+// NewDataAddr returns a memory reference relative to the named data symbol.
+func NewDataAddr(sym Symbol, offset int) Mem {
+ return Mem{
+ Symbol: sym,
+ Disp: offset,
+ Base: reg.StaticBase,
+ }
+}
+
+// Offset returns a reference to m plus idx bytes.
+func (m Mem) Offset(idx int) Mem {
+ a := m
+ a.Disp += idx
+ return a
+}
+
+// Idx returns a new memory reference with (Index, Scale) set to (r, s).
+func (m Mem) Idx(r reg.Register, s uint8) Mem {
+ a := m
+ a.Index = r
+ a.Scale = s
+ return a
+}
+
+// Asm returns an assembly syntax representation of m.
+func (m Mem) Asm() string {
+ a := m.Symbol.String()
+ if a != "" {
+ a += fmt.Sprintf("%+d", m.Disp)
+ } else 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
+}
+
+// Rel is an offset relative to the instruction pointer.
+type Rel int32
+
+// Asm returns an assembly syntax representation of r.
+func (r Rel) Asm() string {
+ return fmt.Sprintf(".%+d", r)
+}
+
+// LabelRef is a reference to a label.
+type LabelRef string
+
+// Asm returns an assembly syntax representation of l.
+func (l LabelRef) Asm() string {
+ return string(l)
+}
+
+// Registers returns the list of all operands involved in the given operand.
+func Registers(op Op) []reg.Register {
+ switch op := op.(type) {
+ case reg.Register:
+ return []reg.Register{op}
+ case Mem:
+ var r []reg.Register
+ if op.Base != nil {
+ r = append(r, op.Base)
+ }
+ if op.Index != nil {
+ r = append(r, op.Index)
+ }
+ return r
+ case Constant, Rel, LabelRef:
+ return nil
+ }
+ panic("unknown operand type")
+}
+
+// ApplyAllocation returns an operand with allocated registers replaced. Registers missing from the allocation are left alone.
+func ApplyAllocation(op Op, a reg.Allocation) Op {
+ switch op := op.(type) {
+ case reg.Register:
+ return a.LookupRegisterDefault(op)
+ case Mem:
+ op.Base = a.LookupRegisterDefault(op.Base)
+ op.Index = a.LookupRegisterDefault(op.Index)
+ return op
+ }
+ return op
+}
diff --git a/vendor/github.com/mmcloughlin/avo/operand/zconst.go b/vendor/github.com/mmcloughlin/avo/operand/zconst.go
new file mode 100644
index 0000000..324b4a9
--- /dev/null
+++ b/vendor/github.com/mmcloughlin/avo/operand/zconst.go
@@ -0,0 +1,75 @@
+// Code generated by make_const.go. DO NOT EDIT.
+
+package operand
+
+import "fmt"
+
+// I8 is a 8-bit signed integer constant.
+type I8 int8
+
+func (i I8) Asm() string { return fmt.Sprintf("$%+d", i) }
+func (i I8) Bytes() int { return 1 }
+func (i I8) constant() {}
+
+// U8 is a 8-bit unsigned integer constant.
+type U8 uint8
+
+func (u U8) Asm() string { return fmt.Sprintf("$%#02x", u) }
+func (u U8) Bytes() int { return 1 }
+func (u U8) constant() {}
+
+// I16 is a 16-bit signed integer constant.
+type I16 int16
+
+func (i I16) Asm() string { return fmt.Sprintf("$%+d", i) }
+func (i I16) Bytes() int { return 2 }
+func (i I16) constant() {}
+
+// U16 is a 16-bit unsigned integer constant.
+type U16 uint16
+
+func (u U16) Asm() string { return fmt.Sprintf("$%#04x", u) }
+func (u U16) Bytes() int { return 2 }
+func (u U16) constant() {}
+
+// F32 is a 32-bit floating point constant.
+type F32 float32
+
+func (f F32) Asm() string { return fmt.Sprintf("$(%#v)", f) }
+func (f F32) Bytes() int { return 4 }
+func (f F32) constant() {}
+
+// I32 is a 32-bit signed integer constant.
+type I32 int32
+
+func (i I32) Asm() string { return fmt.Sprintf("$%+d", i) }
+func (i I32) Bytes() int { return 4 }
+func (i I32) constant() {}
+
+// U32 is a 32-bit unsigned integer constant.
+type U32 uint32
+
+func (u U32) Asm() string { return fmt.Sprintf("$%#08x", u) }
+func (u U32) Bytes() int { return 4 }
+func (u U32) constant() {}
+
+// F64 is a 64-bit floating point constant.
+type F64 float64
+
+func (f F64) Asm() string { return fmt.Sprintf("$(%#v)", f) }
+func (f F64) Bytes() int { return 8 }
+func (f F64) constant() {}
+
+// I64 is a 64-bit signed integer constant.
+type I64 int64
+
+func (i I64) Asm() string { return fmt.Sprintf("$%+d", i) }
+func (i I64) Bytes() int { return 8 }
+func (i I64) constant() {}
+
+// U64 is a 64-bit unsigned integer constant.
+type U64 uint64
+
+func (u U64) Asm() string { return fmt.Sprintf("$%#016x", u) }
+func (u U64) Bytes() int { return 8 }
+func (u U64) constant() {}