Files
avo/operand/checks.go

283 lines
7.1 KiB
Go
Raw Permalink Normal View History

2018-11-26 10:13:04 -08:00
package operand
2026-03-06 20:14:02 +00:00
import "sources.truenas.cloud/code/avo/reg"
2018-11-26 10:13:04 -08:00
2018-12-02 22:29:30 -08:00
// 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.
2018-12-02 12:28:33 -08:00
func Is1(op Op) bool {
2018-12-26 16:42:39 -08:00
i, ok := op.(U8)
return ok && i == 1
2018-11-26 10:13:04 -08:00
}
// Is3 returns true if op is the immediate constant 3.
2018-12-02 12:28:33 -08:00
func Is3(op Op) bool {
2018-12-26 16:42:39 -08:00
i, ok := op.(U8)
return ok && i == 3
2018-11-26 10:13:04 -08:00
}
// IsIMM2U returns true if op is a 2-bit unsigned immediate (less than 4).
func IsIMM2U(op Op) bool {
2018-12-26 16:42:39 -08:00
i, ok := op.(U8)
return ok && i < 4
2018-11-26 10:13:04 -08:00
}
// IsIMM8 returns true is op is an 8-bit immediate.
func IsIMM8(op Op) bool {
_, uok := op.(U8)
_, iok := op.(I8)
return uok || iok
2018-11-26 10:13:04 -08:00
}
// IsIMM16 returns true is op is a 16-bit immediate.
func IsIMM16(op Op) bool {
_, uok := op.(U16)
_, iok := op.(I16)
return uok || iok
2018-11-26 10:13:04 -08:00
}
// IsIMM32 returns true is op is a 32-bit immediate.
func IsIMM32(op Op) bool {
_, uok := op.(U32)
_, iok := op.(I32)
return uok || iok
2018-11-26 10:13:04 -08:00
}
// IsIMM64 returns true is op is a 64-bit immediate.
func IsIMM64(op Op) bool {
_, uok := op.(U64)
_, iok := op.(I64)
return uok || iok
2018-11-26 10:13:04 -08:00
}
// IsAL returns true if op is the AL register.
func IsAL(op Op) bool {
return op == reg.AL
2018-11-26 10:13:04 -08:00
}
// IsCL returns true if op is the CL register.
func IsCL(op Op) bool {
return op == reg.CL
2018-11-26 10:13:04 -08:00
}
// IsAX returns true if op is the 16-bit AX register.
func IsAX(op Op) bool {
return op == reg.AX
2018-11-26 10:13:04 -08:00
}
// IsEAX returns true if op is the 32-bit EAX register.
func IsEAX(op Op) bool {
return op == reg.EAX
2018-11-26 10:13:04 -08:00
}
// IsRAX returns true if op is the 64-bit RAX register.
func IsRAX(op Op) bool {
return op == reg.RAX
2018-11-26 10:13:04 -08:00
}
// IsR8 returns true if op is an 8-bit general-purpose register.
2018-12-02 12:28:33 -08:00
func IsR8(op Op) bool {
return IsGP(op, 1)
2018-11-26 10:13:04 -08:00
}
// IsR16 returns true if op is a 16-bit general-purpose register.
2018-12-02 12:28:33 -08:00
func IsR16(op Op) bool {
return IsGP(op, 2)
2018-11-26 10:13:04 -08:00
}
// IsR32 returns true if op is a 32-bit general-purpose register.
2018-12-02 12:28:33 -08:00
func IsR32(op Op) bool {
return IsGP(op, 4)
2018-11-26 10:13:04 -08:00
}
// IsR64 returns true if op is a 64-bit general-purpose register.
2018-12-02 12:28:33 -08:00
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.
2018-12-02 12:28:33 -08:00
func IsGP(op Op, n uint) bool {
return IsRegisterKindSize(op, reg.KindGP, n)
2018-11-26 10:13:04 -08:00
}
// IsXMM0 returns true if op is the X0 register.
func IsXMM0(op Op) bool {
2018-11-26 23:35:26 -08:00
return op == reg.X0
2018-11-26 10:13:04 -08:00
}
// IsXMM returns true if op is a 128-bit XMM register.
func IsXMM(op Op) bool {
return IsRegisterKindSize(op, reg.KindVector, 16)
2018-11-26 10:13:04 -08:00
}
// IsYMM returns true if op is a 256-bit YMM register.
func IsYMM(op Op) bool {
return IsRegisterKindSize(op, reg.KindVector, 32)
2018-11-26 10:13:04 -08:00
}
all: AVX-512 (#217) Extends avo to support most AVX-512 instruction sets. The instruction type is extended to support suffixes. The K family of opmask registers is added to the register package, and the operand package is updated to support the new operand types. Move instruction deduction in `Load` and `Store` is extended to support KMOV* and VMOV* forms. Internal code generation packages were overhauled. Instruction database loading required various messy changes to account for the additional complexities of the AVX-512 instruction sets. The internal/api package was added to introduce a separation between instruction forms in the database, and the functions avo provides to create them. This was required since with instruction suffixes there is no longer a one-to-one mapping between instruction constructors and opcodes. AVX-512 bloated generated source code size substantially, initially increasing compilation and CI test times to an unacceptable level. Two changes were made to address this: 1. Instruction constructors in the `x86` package moved to an optab-based approach. This compiles substantially faster than the verbose code generation we had before. 2. The most verbose code-generated tests are moved under build tags and limited to a stress test mode. Stress test builds are run on schedule but not in regular CI. An example of AVX-512 accelerated 16-lane MD5 is provided to demonstrate and test the new functionality. Updates #20 #163 #229 Co-authored-by: Vaughn Iverson <vsivsi@yahoo.com>
2021-11-12 18:35:36 -08:00
// 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)
}
2018-11-26 23:35:26 -08:00
// IsRegisterKindSize returns true if op is a register of the given kind and size in bytes.
2018-12-02 12:28:33 -08:00
func IsRegisterKindSize(op Op, k reg.Kind, n uint) bool {
2018-12-02 21:35:33 -08:00
r, ok := op.(reg.Register)
return ok && r.Kind() == k && r.Size() == n
2018-11-26 23:35:26 -08:00
}
2018-12-13 00:18:44 -08:00
// 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
}
2018-11-26 23:35:26 -08:00
// IsM returns true if op is a 16-, 32- or 64-bit memory operand.
2018-12-02 12:28:33 -08:00
func IsM(op Op) bool {
2018-11-26 23:35:26 -08:00
// 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)
2018-11-26 10:13:04 -08:00
}
2018-11-26 23:35:26 -08:00
// IsM8 returns true if op is an 8-bit memory operand.
2018-12-02 12:28:33 -08:00
func IsM8(op Op) bool {
2018-11-26 23:35:26 -08:00
// 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)
2018-11-26 10:13:04 -08:00
}
2018-11-26 23:35:26 -08:00
// IsM16 returns true if op is a 16-bit memory operand.
2018-12-02 12:28:33 -08:00
func IsM16(op Op) bool {
2018-11-26 23:35:26 -08:00
return IsMSize(op, 2)
2018-11-26 10:13:04 -08:00
}
2018-11-26 23:35:26 -08:00
// IsM32 returns true if op is a 16-bit memory operand.
2018-12-02 12:28:33 -08:00
func IsM32(op Op) bool {
2018-11-26 23:35:26 -08:00
return IsMSize(op, 4)
2018-11-26 10:13:04 -08:00
}
2018-11-26 23:35:26 -08:00
// IsM64 returns true if op is a 64-bit memory operand.
2018-12-02 12:28:33 -08:00
func IsM64(op Op) bool {
2018-11-26 23:35:26 -08:00
return IsMSize(op, 8)
2018-11-26 10:13:04 -08:00
}
2018-11-26 23:35:26 -08:00
// IsMSize returns true if op is a memory operand using general-purpose address
// registers of the given size in bytes.
2018-12-02 12:28:33 -08:00
func IsMSize(op Op, n uint) bool {
2018-11-26 23:35:26 -08:00
// TODO(mbm): should memory operands have a size attribute as well?
2018-12-14 22:12:28 -08:00
// TODO(mbm): m8,m16,m32,m64 checks do not actually check size
2018-11-26 23:35:26 -08:00
m, ok := op.(Mem)
2018-12-13 00:18:44 -08:00
return ok && IsMReg(m.Base) && (m.Index == nil || IsMReg(m.Index))
}
2018-12-13 00:18:44 -08:00
// 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)
2018-11-26 23:35:26 -08:00
}
// IsM128 returns true if op is a 128-bit memory operand.
2018-12-02 12:28:33 -08:00
func IsM128(op Op) bool {
2018-11-26 23:35:26 -08:00
// TODO(mbm): should "m128" be the same as "m64"?
return IsM64(op)
2018-11-26 10:13:04 -08:00
}
2018-11-26 23:35:26 -08:00
// IsM256 returns true if op is a 256-bit memory operand.
2018-12-02 12:28:33 -08:00
func IsM256(op Op) bool {
2018-11-26 23:35:26 -08:00
// TODO(mbm): should "m256" be the same as "m64"?
return IsM64(op)
2018-11-26 10:13:04 -08:00
}
all: AVX-512 (#217) Extends avo to support most AVX-512 instruction sets. The instruction type is extended to support suffixes. The K family of opmask registers is added to the register package, and the operand package is updated to support the new operand types. Move instruction deduction in `Load` and `Store` is extended to support KMOV* and VMOV* forms. Internal code generation packages were overhauled. Instruction database loading required various messy changes to account for the additional complexities of the AVX-512 instruction sets. The internal/api package was added to introduce a separation between instruction forms in the database, and the functions avo provides to create them. This was required since with instruction suffixes there is no longer a one-to-one mapping between instruction constructors and opcodes. AVX-512 bloated generated source code size substantially, initially increasing compilation and CI test times to an unacceptable level. Two changes were made to address this: 1. Instruction constructors in the `x86` package moved to an optab-based approach. This compiles substantially faster than the verbose code generation we had before. 2. The most verbose code-generated tests are moved under build tags and limited to a stress test mode. Stress test builds are run on schedule but not in regular CI. An example of AVX-512 accelerated 16-lane MD5 is provided to demonstrate and test the new functionality. Updates #20 #163 #229 Co-authored-by: Vaughn Iverson <vsivsi@yahoo.com>
2021-11-12 18:35:36 -08:00
// 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)
2018-11-26 10:13:04 -08:00
}
// 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.
2018-12-02 12:28:33 -08:00
func IsVmx(op Op) bool {
return isvm(op, IsXMM)
2018-11-26 10:13:04 -08:00
}
// IsVM32Y returns true if op is a vector memory operand with 32-bit YMM index.
func IsVM32Y(op Op) bool {
return IsVmy(op)
2018-11-26 10:13:04 -08:00
}
// 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.
2018-12-02 12:28:33 -08:00
func IsVmy(op Op) bool {
return isvm(op, IsYMM)
}
all: AVX-512 (#217) Extends avo to support most AVX-512 instruction sets. The instruction type is extended to support suffixes. The K family of opmask registers is added to the register package, and the operand package is updated to support the new operand types. Move instruction deduction in `Load` and `Store` is extended to support KMOV* and VMOV* forms. Internal code generation packages were overhauled. Instruction database loading required various messy changes to account for the additional complexities of the AVX-512 instruction sets. The internal/api package was added to introduce a separation between instruction forms in the database, and the functions avo provides to create them. This was required since with instruction suffixes there is no longer a one-to-one mapping between instruction constructors and opcodes. AVX-512 bloated generated source code size substantially, initially increasing compilation and CI test times to an unacceptable level. Two changes were made to address this: 1. Instruction constructors in the `x86` package moved to an optab-based approach. This compiles substantially faster than the verbose code generation we had before. 2. The most verbose code-generated tests are moved under build tags and limited to a stress test mode. Stress test builds are run on schedule but not in regular CI. An example of AVX-512 accelerated 16-lane MD5 is provided to demonstrate and test the new functionality. Updates #20 #163 #229 Co-authored-by: Vaughn Iverson <vsivsi@yahoo.com>
2021-11-12 18:35:36 -08:00
// 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)
}
2018-12-02 12:28:33 -08:00
func isvm(op Op, idx func(Op) bool) bool {
m, ok := op.(Mem)
return ok && IsR64(m.Base) && idx(m.Index)
2018-11-26 10:13:04 -08:00
}
// IsREL8 returns true if op is an 8-bit offset relative to instruction pointer.
func IsREL8(op Op) bool {
2018-11-27 22:08:11 -08:00
r, ok := op.(Rel)
return ok && r == Rel(int8(r))
2018-11-26 10:13:04 -08:00
}
// IsREL32 returns true if op is an offset relative to instruction pointer, or a
2018-11-27 22:08:11 -08:00
// label reference.
func IsREL32(op Op) bool {
2018-11-27 22:08:11 -08:00
// TODO(mbm): should labels be considered separately?
_, rel := op.(Rel)
_, label := op.(LabelRef)
return rel || label
2018-11-26 10:13:04 -08:00
}