diff options
Diffstat (limited to 'vendor/github.com/mmcloughlin/avo/operand')
-rw-r--r-- | vendor/github.com/mmcloughlin/avo/operand/checks.go | 247 | ||||
-rw-r--r-- | vendor/github.com/mmcloughlin/avo/operand/const.go | 36 | ||||
-rw-r--r-- | vendor/github.com/mmcloughlin/avo/operand/doc.go | 2 | ||||
-rw-r--r-- | vendor/github.com/mmcloughlin/avo/operand/types.go | 151 | ||||
-rw-r--r-- | vendor/github.com/mmcloughlin/avo/operand/zconst.go | 75 |
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() {} |