forked from toolshed/abra
chore: go mod vendor / tidy
This commit is contained in:
282
vendor/github.com/mmcloughlin/avo/operand/checks.go
generated
vendored
Normal file
282
vendor/github.com/mmcloughlin/avo/operand/checks.go
generated
vendored
Normal file
@ -0,0 +1,282 @@
|
||||
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 {
|
||||
_, uok := op.(U8)
|
||||
_, iok := op.(I8)
|
||||
return uok || iok
|
||||
}
|
||||
|
||||
// IsIMM16 returns true is op is a 16-bit immediate.
|
||||
func IsIMM16(op Op) bool {
|
||||
_, uok := op.(U16)
|
||||
_, iok := op.(I16)
|
||||
return uok || iok
|
||||
}
|
||||
|
||||
// IsIMM32 returns true is op is a 32-bit immediate.
|
||||
func IsIMM32(op Op) bool {
|
||||
_, uok := op.(U32)
|
||||
_, iok := op.(I32)
|
||||
return uok || iok
|
||||
}
|
||||
|
||||
// IsIMM64 returns true is op is a 64-bit immediate.
|
||||
func IsIMM64(op Op) bool {
|
||||
_, uok := op.(U64)
|
||||
_, iok := op.(I64)
|
||||
return uok || iok
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// IsZMM returns true if op is a 512-bit ZMM register.
|
||||
func IsZMM(op Op) bool {
|
||||
return IsRegisterKindSize(op, reg.KindVector, 64)
|
||||
}
|
||||
|
||||
// IsK returns true if op is an Opmask register.
|
||||
func IsK(op Op) bool {
|
||||
return IsRegisterKind(op, reg.KindOpmask)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// IsM512 returns true if op is a 512-bit memory operand.
|
||||
func IsM512(op Op) bool {
|
||||
// TODO(mbm): should "m512" 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)
|
||||
}
|
||||
|
||||
// IsVM32Z returns true if op is a vector memory operand with 32-bit ZMM index.
|
||||
func IsVM32Z(op Op) bool {
|
||||
return IsVmz(op)
|
||||
}
|
||||
|
||||
// IsVM64Z returns true if op is a vector memory operand with 64-bit ZMM index.
|
||||
func IsVM64Z(op Op) bool {
|
||||
return IsVmz(op)
|
||||
}
|
||||
|
||||
// IsVmz returns true if op is a vector memory operand with ZMM index.
|
||||
func IsVmz(op Op) bool {
|
||||
return isvm(op, IsZMM)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
64
vendor/github.com/mmcloughlin/avo/operand/const.go
generated
vendored
Normal file
64
vendor/github.com/mmcloughlin/avo/operand/const.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
package operand
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Constant represents a constant literal.
|
||||
type Constant interface {
|
||||
Op
|
||||
Bytes() int
|
||||
constant()
|
||||
}
|
||||
|
||||
//go:generate go run make_const.go -output zconst.go
|
||||
|
||||
// Special cases for floating point string representation.
|
||||
//
|
||||
// Issue 387 pointed out that floating point values that happen to be integers
|
||||
// need to have a decimal point to be parsed correctly.
|
||||
|
||||
// String returns a representation the 32-bit float which is guaranteed to be
|
||||
// parsed as a floating point constant by the Go assembler.
|
||||
func (f F32) String() string { return asmfloat(float64(f), 32) }
|
||||
|
||||
// String returns a representation the 64-bit float which is guaranteed to be
|
||||
// parsed as a floating point constant by the Go assembler.
|
||||
func (f F64) String() string { return asmfloat(float64(f), 64) }
|
||||
|
||||
// asmfloat represents x as a string such that the assembler scanner will always
|
||||
// recognize it as a float. Specifically, ensure that when x is an integral
|
||||
// value, the result will still have a decimal point.
|
||||
func asmfloat(x float64, bits int) string {
|
||||
s := strconv.FormatFloat(x, 'f', -1, bits)
|
||||
if !strings.ContainsRune(s, '.') {
|
||||
s += ".0"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
2
vendor/github.com/mmcloughlin/avo/operand/doc.go
generated
vendored
Normal file
2
vendor/github.com/mmcloughlin/avo/operand/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package operand provides types for instruction operands.
|
||||
package operand
|
151
vendor/github.com/mmcloughlin/avo/operand/types.go
generated
vendored
Normal file
151
vendor/github.com/mmcloughlin/avo/operand/types.go
generated
vendored
Normal file
@ -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
|
||||
}
|
75
vendor/github.com/mmcloughlin/avo/operand/zconst.go
generated
vendored
Normal file
75
vendor/github.com/mmcloughlin/avo/operand/zconst.go
generated
vendored
Normal file
@ -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("$(%s)", 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("$(%s)", 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() {}
|
Reference in New Issue
Block a user