Signed-off-by: Achille Roussel <achille.roussel@gmail.com> Co-authored-by: Crypt Keeper <64215+codefromthecrypt@users.noreply.github.com>
4114 lines
102 KiB
Go
4114 lines
102 KiB
Go
package arm64
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"testing"
|
|
|
|
"github.com/tetratelabs/wazero/internal/asm"
|
|
"github.com/tetratelabs/wazero/internal/testing/require"
|
|
)
|
|
|
|
func TestNodePool_allocNode(t *testing.T) {
|
|
np := nodePool{index: nodePageSize}
|
|
|
|
for i := 0; i < nodePageSize; i++ {
|
|
n := np.allocNode()
|
|
require.Equal(t, &np.pages[0][i], n)
|
|
require.Equal(t, i+1, np.index)
|
|
require.Equal(t, 1, len(np.pages))
|
|
}
|
|
require.Equal(t, nodePageSize, np.index)
|
|
|
|
// Reached the next page.
|
|
secondPageBegin := np.allocNode()
|
|
require.Equal(t, 1, np.index)
|
|
require.Equal(t, 2, len(np.pages))
|
|
require.Equal(t, &np.pages[1][0], secondPageBegin)
|
|
}
|
|
|
|
func TestAssemblerImpl_Reset(t *testing.T) {
|
|
// Existing values.
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
buf := code.NextCodeSection()
|
|
buf.AppendBytes([]byte{0, 0, 0, 0, 0})
|
|
|
|
staticConsts := asm.NewStaticConstPool()
|
|
staticConsts.AddConst(asm.NewStaticConst(nil), 1234)
|
|
adrInstructionNodes := make([]*nodeImpl, 5)
|
|
relativeJumpNodes := make([]*nodeImpl, 10)
|
|
ba := asm.BaseAssemblerImpl{
|
|
SetBranchTargetOnNextNodes: make([]asm.Node, 5),
|
|
JumpTableEntries: make([]asm.JumpTableEntry, 10),
|
|
}
|
|
|
|
// Create assembler and reset.
|
|
a := &AssemblerImpl{
|
|
nodePool: nodePool{
|
|
pages: []*nodePage{new(nodePage), new(nodePage)},
|
|
index: 12,
|
|
},
|
|
pool: staticConsts,
|
|
temporaryRegister: RegV2,
|
|
relativeJumpNodes: relativeJumpNodes,
|
|
adrInstructionNodes: adrInstructionNodes,
|
|
BaseAssemblerImpl: ba,
|
|
}
|
|
a.Reset()
|
|
buf.Reset()
|
|
|
|
// Check each field.
|
|
require.Equal(t, 65536, buf.Cap())
|
|
require.Equal(t, 0, buf.Len())
|
|
|
|
require.Zero(t, len(a.nodePool.pages))
|
|
require.Equal(t, nodePageSize, a.nodePool.index)
|
|
|
|
require.NotEqual(t, staticConsts, a.pool)
|
|
|
|
require.Equal(t, RegV2, a.temporaryRegister)
|
|
|
|
require.Equal(t, 0, len(a.adrInstructionNodes))
|
|
require.Equal(t, cap(adrInstructionNodes), cap(a.adrInstructionNodes))
|
|
|
|
require.Equal(t, 0, len(a.relativeJumpNodes))
|
|
require.Equal(t, cap(relativeJumpNodes), cap(a.relativeJumpNodes))
|
|
|
|
require.Equal(t, 0, len(a.SetBranchTargetOnNextNodes))
|
|
require.Equal(t, cap(ba.SetBranchTargetOnNextNodes), cap(a.SetBranchTargetOnNextNodes))
|
|
|
|
require.Equal(t, 0, len(a.JumpTableEntries))
|
|
require.Equal(t, cap(ba.JumpTableEntries), cap(a.JumpTableEntries))
|
|
}
|
|
|
|
func TestNodeImpl_AssignJumpTarget(t *testing.T) {
|
|
n := &nodeImpl{}
|
|
target := &nodeImpl{}
|
|
n.AssignJumpTarget(target)
|
|
require.Equal(t, n.jumpTarget, target)
|
|
}
|
|
|
|
func TestNodeImpl_AssignDestinationConstant(t *testing.T) {
|
|
n := &nodeImpl{}
|
|
n.AssignDestinationConstant(12345)
|
|
require.Equal(t, int64(12345), n.dstConst)
|
|
}
|
|
|
|
func TestNodeImpl_AssignSourceConstant(t *testing.T) {
|
|
n := &nodeImpl{}
|
|
n.AssignSourceConstant(12345)
|
|
require.Equal(t, int64(12345), n.srcConst)
|
|
}
|
|
|
|
func TestNodeImpl_String(t *testing.T) {
|
|
tests := []struct {
|
|
in *nodeImpl
|
|
exp string
|
|
}{
|
|
{
|
|
in: &nodeImpl{instruction: NOP, types: operandTypesNoneToNone},
|
|
exp: "NOP",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: BCONDEQ, types: operandTypesNoneToRegister, dstReg: RegR1},
|
|
exp: "BCONDEQ R1",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: BCONDNE, types: operandTypesNoneToBranch, jumpTarget: &nodeImpl{instruction: NOP}},
|
|
exp: "BCONDNE {NOP}",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: ADD, types: operandTypesRegisterToRegister, srcReg: RegV0, dstReg: RegV10},
|
|
exp: "ADD V0, V10",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: ADD, types: operandTypesLeftShiftedRegisterToRegister,
|
|
srcReg: RegR0, srcReg2: RegR11, srcConst: 4, dstReg: RegR10,
|
|
},
|
|
exp: "ADD (R0, R11 << 4), R10",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: ADD, types: operandTypesTwoRegistersToRegister, srcReg: RegR0, srcReg2: RegR8, dstReg: RegR10},
|
|
exp: "ADD (R0, R8), R10",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: MSUB, types: operandTypesThreeRegistersToRegister,
|
|
srcReg: RegR0, srcReg2: RegR8, dstReg: RegR10, dstReg2: RegR1,
|
|
},
|
|
exp: "MSUB (R0, R8, R10), R1)",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: CMPW, types: operandTypesTwoRegistersToNone, srcReg: RegR0, srcReg2: RegR8},
|
|
exp: "CMPW (R0, R8)",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: CMP, types: operandTypesRegisterAndConstToNone, srcReg: RegR0, srcConst: 0x123},
|
|
exp: "CMP (R0, 0x123)",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: MOVD, types: operandTypesRegisterToMemory, srcReg: RegR0, dstReg: RegR8, dstConst: 0x123},
|
|
exp: "MOVD R0, [R8 + 0x123]",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: MOVD, types: operandTypesRegisterToMemory, srcReg: RegR0, dstReg: RegR8, dstReg2: RegR6},
|
|
exp: "MOVD R0, [R8 + R6]",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: MOVD, types: operandTypesMemoryToRegister, srcReg: RegR0, srcConst: 0x123, dstReg: RegR8},
|
|
exp: "MOVD [R0 + 0x123], R8",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: MOVD, types: operandTypesMemoryToRegister, srcReg: RegR0, srcReg2: RegR6, dstReg: RegR8},
|
|
exp: "MOVD [R0 + R6], R8",
|
|
},
|
|
{
|
|
in: &nodeImpl{instruction: MOVD, types: operandTypesConstToRegister, srcConst: 0x123, dstReg: RegR8},
|
|
exp: "MOVD 0x123, R8",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: VMOV, types: operandTypesMemoryToVectorRegister,
|
|
srcReg: RegR1, dstReg: RegV29, vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: "VMOV [R1], V29.2S",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: VMOV, types: operandTypesVectorRegisterToMemory,
|
|
dstReg: RegR1, dstReg2: RegR6,
|
|
srcReg: RegV29, vectorArrangement: VectorArrangementQ,
|
|
},
|
|
exp: "VMOV V29.Q, [R1 + R6]",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: VMOV, types: operandTypesVectorRegisterToMemory,
|
|
dstReg: RegR1, dstConst: 0x10,
|
|
srcReg: RegV29, vectorArrangement: VectorArrangementQ,
|
|
},
|
|
exp: "VMOV V29.Q, [R1 + 0x10]",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: VMOV, types: operandTypesRegisterToVectorRegister,
|
|
srcReg: RegR1, dstReg: RegV29, vectorArrangement: VectorArrangement2D, dstVectorIndex: 1,
|
|
},
|
|
exp: "VMOV R1, V29.2D[1]",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: VCNT, types: operandTypesVectorRegisterToVectorRegister,
|
|
srcReg: RegV3, dstReg: RegV29, vectorArrangement: VectorArrangement2D, srcVectorIndex: 1,
|
|
},
|
|
exp: "VCNT V3.2D, V29.2D",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: VCNT, types: operandTypesVectorRegisterToVectorRegister,
|
|
srcReg: RegV3, dstReg: RegV29, vectorArrangement: VectorArrangement2D, srcVectorIndex: 1,
|
|
},
|
|
exp: "VCNT V3.2D, V29.2D",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: UMOV, types: operandTypesVectorRegisterToRegister,
|
|
srcReg: RegV31, dstReg: RegR8, vectorArrangement: VectorArrangementS, srcVectorIndex: 1,
|
|
},
|
|
exp: "UMOV V31.S[1], R8",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: UMOV, types: operandTypesTwoVectorRegistersToVectorRegister,
|
|
srcReg: RegV31, srcReg2: RegV1, dstReg: RegV8, vectorArrangement: VectorArrangementS, srcVectorIndex: 1,
|
|
},
|
|
exp: "UMOV (V31.S, V1.S), V8.S",
|
|
},
|
|
{
|
|
in: &nodeImpl{
|
|
instruction: VORR, types: operandTypesStaticConstToVectorRegister,
|
|
staticConst: &asm.StaticConst{Raw: []byte{1, 2, 3, 4}},
|
|
dstReg: RegV8, vectorArrangement: VectorArrangement16B, srcVectorIndex: 1,
|
|
},
|
|
exp: "VORR $0x01020304 V8.16B",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.exp, func(t *testing.T) {
|
|
require.Equal(t, tc.exp, tc.in.String())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_addNode(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
|
|
root := &nodeImpl{}
|
|
a.addNode(root)
|
|
require.Equal(t, a.root, root)
|
|
require.Equal(t, a.current, root)
|
|
require.Nil(t, root.next)
|
|
|
|
next := &nodeImpl{}
|
|
a.addNode(next)
|
|
require.Equal(t, a.root, root)
|
|
require.Equal(t, a.current, next)
|
|
require.Equal(t, next, root.next)
|
|
require.Nil(t, next.next)
|
|
}
|
|
|
|
func TestAssemblerImpl_newNode(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
actual := a.newNode(MOVD, operandTypesMemoryToRegister)
|
|
require.Equal(t, MOVD, actual.instruction)
|
|
require.Equal(t, operandTypesMemoryToRegister, actual.types)
|
|
require.Equal(t, actual, a.root)
|
|
require.Equal(t, actual, a.current)
|
|
}
|
|
|
|
func TestAssemblerImpl_CompileStandAlone(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileStandAlone(RET)
|
|
actualNode := a.current
|
|
require.Equal(t, RET, actualNode.instruction)
|
|
require.Equal(t, operandTypesNoneToNone, actualNode.types)
|
|
}
|
|
|
|
func TestAssemblerImpl_CompileConstToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileConstToRegister(MOVD, 1000, RegR10)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, int64(1000), actualNode.srcConst)
|
|
require.Equal(t, RegR10, actualNode.dstReg)
|
|
require.Equal(t, operandTypesConstToRegister, actualNode.types)
|
|
}
|
|
|
|
func TestAssemblerImpl_CompileRegisterToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileRegisterToRegister(MOVD, RegR15, RegR27)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, RegR15, actualNode.srcReg)
|
|
require.Equal(t, RegR27, actualNode.dstReg)
|
|
require.Equal(t, operandTypesRegisterToRegister, actualNode.types)
|
|
}
|
|
|
|
func TestAssemblerImpl_CompileMemoryToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileMemoryToRegister(MOVD, RegR15, 100, RegR27)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, RegR15, actualNode.srcReg)
|
|
require.Equal(t, int64(100), actualNode.srcConst)
|
|
require.Equal(t, RegR27, actualNode.dstReg)
|
|
require.Equal(t, operandTypesMemoryToRegister, actualNode.types)
|
|
}
|
|
|
|
func TestAssemblerImpl_CompileRegisterToMemory(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileRegisterToMemory(MOVD, RegR15, RegR27, 100)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, RegR15, actualNode.srcReg)
|
|
require.Equal(t, RegR27, actualNode.dstReg)
|
|
require.Equal(t, int64(100), actualNode.dstConst)
|
|
require.Equal(t, operandTypesRegisterToMemory, actualNode.types)
|
|
}
|
|
|
|
func TestAssemblerImpl_CompileJump(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileJump(B)
|
|
actualNode := a.current
|
|
require.Equal(t, B, actualNode.instruction)
|
|
require.Equal(t, operandTypesNoneToBranch, actualNode.types)
|
|
}
|
|
|
|
func TestAssemblerImpl_CompileJumpToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileJumpToRegister(BCONDNE, RegR27)
|
|
actualNode := a.current
|
|
require.Equal(t, BCONDNE, actualNode.instruction)
|
|
require.Equal(t, RegR27, actualNode.dstReg)
|
|
require.Equal(t, operandTypesNoneToRegister, actualNode.types)
|
|
}
|
|
|
|
func TestAssemblerImpl_CompileReadInstructionAddress(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileReadInstructionAddress(RegR10, RET)
|
|
actualNode := a.current
|
|
require.Equal(t, ADR, actualNode.instruction)
|
|
require.Equal(t, RegR10, actualNode.dstReg)
|
|
require.Equal(t, operandTypesMemoryToRegister, actualNode.types)
|
|
require.Equal(t, RET, actualNode.readInstructionAddressBeforeTargetInstruction)
|
|
}
|
|
|
|
func Test_CompileMemoryWithRegisterOffsetToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileMemoryWithRegisterOffsetToRegister(MOVD, RegR27, RegR10, RegR0)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, RegR27, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.srcReg2)
|
|
require.Equal(t, RegR0, actualNode.dstReg)
|
|
require.Equal(t, operandTypesMemoryToRegister, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileMemoryWithRegisterOffsetToVectorRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileMemoryWithRegisterOffsetToVectorRegister(MOVD, RegR27, RegR10, RegV31, VectorArrangementS)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, RegR27, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.srcReg2)
|
|
require.Equal(t, RegV31, actualNode.dstReg)
|
|
require.Equal(t, VectorArrangementS, actualNode.vectorArrangement)
|
|
require.Equal(t, operandTypesMemoryToVectorRegister, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileRegisterToMemoryWithRegisterOffset(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileRegisterToMemoryWithRegisterOffset(MOVD, RegR27, RegR10, RegR0)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, RegR27, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.dstReg)
|
|
require.Equal(t, RegR0, actualNode.dstReg2)
|
|
require.Equal(t, operandTypesRegisterToMemory, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileVectorRegisterToMemoryWithRegisterOffset(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileVectorRegisterToMemoryWithRegisterOffset(MOVD, RegV31, RegR10, RegR0, VectorArrangement2D)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, RegV31, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.dstReg)
|
|
require.Equal(t, RegR0, actualNode.dstReg2)
|
|
require.Equal(t, VectorArrangement2D, actualNode.vectorArrangement)
|
|
require.Equal(t, operandTypesVectorRegisterToMemory, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileTwoRegistersToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileTwoRegistersToRegister(MOVD, RegR27, RegR10, RegR0)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, RegR27, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.srcReg2)
|
|
require.Equal(t, RegR0, actualNode.dstReg)
|
|
require.Equal(t, operandTypesTwoRegistersToRegister, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileThreeRegistersToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileThreeRegistersToRegister(MOVD, RegR27, RegR10, RegR0, RegR28)
|
|
actualNode := a.current
|
|
require.Equal(t, MOVD, actualNode.instruction)
|
|
require.Equal(t, RegR27, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.srcReg2)
|
|
require.Equal(t, RegR0, actualNode.dstReg)
|
|
require.Equal(t, RegR28, actualNode.dstReg2)
|
|
require.Equal(t, operandTypesThreeRegistersToRegister, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileTwoRegistersToNone(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileTwoRegistersToNone(CMP, RegR27, RegR10)
|
|
actualNode := a.current
|
|
require.Equal(t, CMP, actualNode.instruction)
|
|
require.Equal(t, RegR27, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.srcReg2)
|
|
require.Equal(t, operandTypesTwoRegistersToNone, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileRegisterAndConstToNone(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileRegisterAndConstToNone(CMP, RegR27, 10)
|
|
actualNode := a.current
|
|
require.Equal(t, CMP, actualNode.instruction)
|
|
require.Equal(t, RegR27, actualNode.srcReg)
|
|
require.Equal(t, int64(10), actualNode.srcConst)
|
|
require.Equal(t, operandTypesRegisterAndConstToNone, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileRegisterAndConstToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileRegisterAndConstToRegister(CMP, RegR27, 10, RegSP)
|
|
actualNode := a.current
|
|
require.Equal(t, CMP, actualNode.instruction)
|
|
require.Equal(t, RegR27, actualNode.srcReg)
|
|
require.Equal(t, int64(10), actualNode.srcConst)
|
|
require.Equal(t, RegSP, actualNode.dstReg)
|
|
require.Equal(t, operandTypesRegisterAndConstToRegister, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileLeftShiftedRegisterToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileLeftShiftedRegisterToRegister(ADD, RegR27, 10, RegR28, RegR5)
|
|
actualNode := a.current
|
|
require.Equal(t, ADD, actualNode.instruction)
|
|
require.Equal(t, RegR28, actualNode.srcReg)
|
|
require.Equal(t, RegR27, actualNode.srcReg2)
|
|
require.Equal(t, int64(10), actualNode.srcConst)
|
|
require.Equal(t, RegR5, actualNode.dstReg)
|
|
require.Equal(t, operandTypesLeftShiftedRegisterToRegister, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileConditionalRegisterSet(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileConditionalRegisterSet(CondNE, RegR10)
|
|
actualNode := a.current
|
|
require.Equal(t, CSET, actualNode.instruction)
|
|
require.Equal(t, RegCondNE, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.dstReg)
|
|
require.Equal(t, operandTypesRegisterToRegister, actualNode.types)
|
|
}
|
|
|
|
func Test_CompileMemoryToVectorRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileMemoryToVectorRegister(VMOV, RegR10, 10, RegV3, VectorArrangement1D)
|
|
actualNode := a.current
|
|
require.Equal(t, VMOV, actualNode.instruction)
|
|
require.Equal(t, RegR10, actualNode.srcReg)
|
|
require.Equal(t, int64(10), actualNode.srcConst)
|
|
require.Equal(t, RegV3, actualNode.dstReg)
|
|
require.Equal(t, operandTypesMemoryToVectorRegister, actualNode.types)
|
|
require.Equal(t, VectorArrangement1D, actualNode.vectorArrangement)
|
|
}
|
|
|
|
func Test_CompileVectorRegisterToMemory(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileVectorRegisterToMemory(VMOV, RegV3, RegR10, 12, VectorArrangement1D)
|
|
actualNode := a.current
|
|
require.Equal(t, VMOV, actualNode.instruction)
|
|
require.Equal(t, RegV3, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.dstReg)
|
|
require.Equal(t, int64(12), actualNode.dstConst)
|
|
require.Equal(t, operandTypesVectorRegisterToMemory, actualNode.types)
|
|
require.Equal(t, VectorArrangement1D, actualNode.vectorArrangement)
|
|
}
|
|
|
|
func Test_CompileRegisterToVectorRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileRegisterToVectorRegister(VMOV, RegV3, RegR10, VectorArrangement1D, 10)
|
|
actualNode := a.current
|
|
require.Equal(t, VMOV, actualNode.instruction)
|
|
require.Equal(t, RegV3, actualNode.srcReg)
|
|
require.Equal(t, RegR10, actualNode.dstReg)
|
|
require.Equal(t, operandTypesRegisterToVectorRegister, actualNode.types)
|
|
require.Equal(t, VectorArrangement1D, actualNode.vectorArrangement)
|
|
require.Equal(t, VectorIndex(10), actualNode.dstVectorIndex)
|
|
}
|
|
|
|
func Test_CompileVectorRegisterToRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileVectorRegisterToRegister(VMOV, RegR10, RegV3, VectorArrangement1D, 10)
|
|
actualNode := a.current
|
|
require.Equal(t, VMOV, actualNode.instruction)
|
|
require.Equal(t, RegR10, actualNode.srcReg)
|
|
require.Equal(t, RegV3, actualNode.dstReg)
|
|
require.Equal(t, operandTypesVectorRegisterToRegister, actualNode.types)
|
|
require.Equal(t, VectorArrangement1D, actualNode.vectorArrangement)
|
|
require.Equal(t, VectorIndex(10), actualNode.srcVectorIndex)
|
|
}
|
|
|
|
func Test_CompileVectorRegisterToVectorRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileVectorRegisterToVectorRegister(VMOV, RegV3, RegV10, VectorArrangement1D, 1, 2)
|
|
actualNode := a.current
|
|
require.Equal(t, VMOV, actualNode.instruction)
|
|
require.Equal(t, RegV3, actualNode.srcReg)
|
|
require.Equal(t, RegV10, actualNode.dstReg)
|
|
require.Equal(t, operandTypesVectorRegisterToVectorRegister, actualNode.types)
|
|
require.Equal(t, VectorArrangement1D, actualNode.vectorArrangement)
|
|
require.Equal(t, VectorIndex(1), actualNode.srcVectorIndex)
|
|
require.Equal(t, VectorIndex(2), actualNode.dstVectorIndex)
|
|
}
|
|
|
|
func Test_CompileVectorRegisterToVectorRegisterWithConst(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileVectorRegisterToVectorRegisterWithConst(VMOV, RegV3, RegV10, VectorArrangement1D, 1234)
|
|
actualNode := a.current
|
|
require.Equal(t, VMOV, actualNode.instruction)
|
|
require.Equal(t, RegV3, actualNode.srcReg)
|
|
require.Equal(t, RegV10, actualNode.dstReg)
|
|
require.Equal(t, operandTypesVectorRegisterToVectorRegister, actualNode.types)
|
|
require.Equal(t, VectorArrangement1D, actualNode.vectorArrangement)
|
|
require.Equal(t, int64(1234), actualNode.srcConst)
|
|
}
|
|
|
|
func Test_CompileTwoVectorRegistersToVectorRegister(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileTwoVectorRegistersToVectorRegister(VMOV, RegV3, RegV15, RegV10, VectorArrangement1D)
|
|
actualNode := a.current
|
|
require.Equal(t, VMOV, actualNode.instruction)
|
|
require.Equal(t, RegV3, actualNode.srcReg)
|
|
require.Equal(t, RegV15, actualNode.srcReg2)
|
|
require.Equal(t, RegV10, actualNode.dstReg)
|
|
require.Equal(t, operandTypesTwoVectorRegistersToVectorRegister, actualNode.types)
|
|
require.Equal(t, VectorArrangement1D, actualNode.vectorArrangement)
|
|
}
|
|
|
|
func Test_CompileTwoVectorRegistersToVectorRegisterWithConst(t *testing.T) {
|
|
a := NewAssembler(RegR10)
|
|
a.CompileTwoVectorRegistersToVectorRegisterWithConst(VMOV, RegV3, RegV15, RegV10, VectorArrangement1D, 1234)
|
|
actualNode := a.current
|
|
require.Equal(t, VMOV, actualNode.instruction)
|
|
require.Equal(t, RegV3, actualNode.srcReg)
|
|
require.Equal(t, RegV15, actualNode.srcReg2)
|
|
require.Equal(t, int64(1234), actualNode.srcConst)
|
|
require.Equal(t, RegV10, actualNode.dstReg)
|
|
require.Equal(t, operandTypesTwoVectorRegistersToVectorRegister, actualNode.types)
|
|
require.Equal(t, VectorArrangement1D, actualNode.vectorArrangement)
|
|
}
|
|
|
|
func Test_CompileStaticConstToVectorRegister(t *testing.T) {
|
|
s := asm.NewStaticConst([]byte{1, 2, 3, 4})
|
|
a := NewAssembler(RegR10)
|
|
a.CompileStaticConstToVectorRegister(VMOV, s, RegV3, VectorArrangement2D)
|
|
actualNode := a.current
|
|
require.Equal(t, VMOV, actualNode.instruction)
|
|
require.Equal(t, s, actualNode.staticConst)
|
|
require.Equal(t, RegV3, actualNode.dstReg)
|
|
require.Equal(t, operandTypesStaticConstToVectorRegister, actualNode.types)
|
|
require.Equal(t, VectorArrangement2D, actualNode.vectorArrangement)
|
|
}
|
|
|
|
func Test_CompileStaticConstToRegister(t *testing.T) {
|
|
s := asm.NewStaticConst([]byte{1, 2, 3, 4})
|
|
a := NewAssembler(RegR10)
|
|
a.CompileStaticConstToRegister(ADR, s, RegR27)
|
|
actualNode := a.current
|
|
require.Equal(t, ADR, actualNode.instruction)
|
|
require.Equal(t, s, actualNode.staticConst)
|
|
require.Equal(t, RegR27, actualNode.dstReg)
|
|
require.Equal(t, operandTypesMemoryToRegister, actualNode.types)
|
|
}
|
|
|
|
func Test_checkRegisterToRegisterType(t *testing.T) {
|
|
tests := []struct {
|
|
expErr string
|
|
src asm.Register
|
|
dst asm.Register
|
|
requireSrcInt bool
|
|
requireDstInt bool
|
|
}{
|
|
{src: RegR10, dst: RegR30, requireSrcInt: true, requireDstInt: true, expErr: ""},
|
|
{src: RegR10, dst: RegR30, requireSrcInt: false, requireDstInt: true, expErr: "src requires float register but got R10"},
|
|
{src: RegR10, dst: RegR30, requireSrcInt: false, requireDstInt: false, expErr: "src requires float register but got R10"},
|
|
{src: RegR10, dst: RegR30, requireSrcInt: true, requireDstInt: false, expErr: "dst requires float register but got R30"},
|
|
|
|
{src: RegR10, dst: RegV30, requireSrcInt: true, requireDstInt: false, expErr: ""},
|
|
{src: RegR10, dst: RegV30, requireSrcInt: false, requireDstInt: true, expErr: "src requires float register but got R10"},
|
|
{src: RegR10, dst: RegV30, requireSrcInt: false, requireDstInt: false, expErr: "src requires float register but got R10"},
|
|
{src: RegR10, dst: RegV30, requireSrcInt: true, requireDstInt: true, expErr: "dst requires int register but got V30"},
|
|
|
|
{src: RegV10, dst: RegR30, requireSrcInt: false, requireDstInt: true, expErr: ""},
|
|
{src: RegV10, dst: RegR30, requireSrcInt: true, requireDstInt: true, expErr: "src requires int register but got V10"},
|
|
{src: RegV10, dst: RegR30, requireSrcInt: true, requireDstInt: false, expErr: "src requires int register but got V10"},
|
|
{src: RegV10, dst: RegR30, requireSrcInt: false, requireDstInt: false, expErr: "dst requires float register but got R30"},
|
|
|
|
{src: RegV10, dst: RegV30, requireSrcInt: false, requireDstInt: false, expErr: ""},
|
|
{src: RegV10, dst: RegV30, requireSrcInt: true, requireDstInt: false, expErr: "src requires int register but got V10"},
|
|
{src: RegV10, dst: RegV30, requireSrcInt: true, requireDstInt: true, expErr: "src requires int register but got V10"},
|
|
{src: RegV10, dst: RegV30, requireSrcInt: false, requireDstInt: true, expErr: "dst requires int register but got V30"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
actual := checkRegisterToRegisterType(tc.src, tc.dst, tc.requireSrcInt, tc.requireDstInt)
|
|
if tc.expErr != "" {
|
|
require.EqualError(t, actual, tc.expErr)
|
|
} else {
|
|
require.NoError(t, actual)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_encodeNoneToNone(t *testing.T) {
|
|
t.Run("error", func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeNoneToNone(buf, &nodeImpl{instruction: ADD})
|
|
require.EqualError(t, err, "ADD is unsupported for NoneToNone type")
|
|
})
|
|
t.Run("NOP", func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeNoneToNone(buf, &nodeImpl{instruction: NOP})
|
|
require.NoError(t, err)
|
|
|
|
// NOP must be ignored.
|
|
actual := buf.Bytes()
|
|
require.Zero(t, len(actual))
|
|
})
|
|
t.Run("UDF", func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeNoneToNone(buf, &nodeImpl{instruction: UDF})
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, []byte{0x0, 0x0, 0x0, 0x0}, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
|
|
func Test_validateMemoryOffset(t *testing.T) {
|
|
tests := []struct {
|
|
expErr string
|
|
offset int64
|
|
}{
|
|
{offset: 0},
|
|
{offset: -256},
|
|
{offset: 255},
|
|
{offset: 123 * 8},
|
|
{offset: 123 * 4},
|
|
{offset: -257, expErr: "negative memory offset must be larget than or equal -256 but got -257"},
|
|
{offset: 257, expErr: "large memory offset (>255) must be a multiple of 4 but got 257"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
actual := validateMemoryOffset(tc.offset)
|
|
if tc.expErr == "" {
|
|
require.NoError(t, actual)
|
|
} else {
|
|
require.EqualError(t, actual, tc.expErr)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_EncodeVectorRegisterToMemory(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
n *nodeImpl
|
|
exp []byte
|
|
}{
|
|
// Register offset cases.
|
|
{
|
|
name: "str b11, [x12, x6]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV11,
|
|
dstReg: RegR12,
|
|
dstReg2: RegR6,
|
|
vectorArrangement: VectorArrangementB,
|
|
},
|
|
exp: []byte{0x8b, 0x69, 0x26, 0x3c},
|
|
},
|
|
{
|
|
name: "str h11, [x12, x6]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV11,
|
|
dstReg: RegR0,
|
|
dstReg2: RegR6,
|
|
vectorArrangement: VectorArrangementH,
|
|
},
|
|
exp: []byte{0xb, 0x68, 0x26, 0x7c},
|
|
},
|
|
{
|
|
name: "str s11, [x29, x6]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV11,
|
|
dstReg: RegR29,
|
|
dstReg2: RegR6,
|
|
vectorArrangement: VectorArrangementS,
|
|
},
|
|
exp: []byte{0xab, 0x6b, 0x26, 0xbc},
|
|
},
|
|
{
|
|
name: "str d0, [x0, x0]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV0,
|
|
dstReg: RegR0,
|
|
dstReg2: RegR0,
|
|
vectorArrangement: VectorArrangementD,
|
|
},
|
|
exp: []byte{0x0, 0x68, 0x20, 0xfc},
|
|
},
|
|
{
|
|
name: "str q30, [x30, x29]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV30,
|
|
dstReg: RegR30,
|
|
dstReg2: RegR29,
|
|
vectorArrangement: VectorArrangementQ,
|
|
},
|
|
exp: []byte{0xde, 0x6b, 0xbd, 0x3c},
|
|
},
|
|
// Constant offset cases.
|
|
{
|
|
name: "str b11, [x12, #0x7b]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV11,
|
|
dstReg: RegR12,
|
|
dstConst: 0x7b,
|
|
vectorArrangement: VectorArrangementB,
|
|
},
|
|
exp: []byte{0x8b, 0xed, 0x1, 0x3d},
|
|
},
|
|
{
|
|
name: "ldr w10, #0xc ; str h11, [x12, x10]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV11,
|
|
dstReg: RegR12,
|
|
dstConst: 1 << 30,
|
|
vectorArrangement: VectorArrangementH,
|
|
},
|
|
exp: []byte{0x6a, 0x0, 0x0, 0x18, 0x8b, 0x69, 0x2a, 0x7c, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x40},
|
|
},
|
|
{
|
|
name: "ldr w10, #0xc ; str s11, [x12, x10]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV11,
|
|
dstReg: RegR12,
|
|
dstConst: (1 << 28) + 4,
|
|
vectorArrangement: VectorArrangementS,
|
|
},
|
|
exp: []byte{0x6a, 0x0, 0x0, 0x18, 0x8b, 0x69, 0x2a, 0xbc, 0x0, 0x0, 0x0, 0x14, 0x4, 0x0, 0x0, 0x10},
|
|
},
|
|
{
|
|
name: "str d11, [x12, #0x3d8]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV11,
|
|
dstReg: RegR12,
|
|
dstConst: 0x3d8,
|
|
vectorArrangement: VectorArrangementD,
|
|
},
|
|
exp: []byte{0x8b, 0xed, 0x1, 0xfd},
|
|
},
|
|
{
|
|
name: "stur q1, [x30, #1]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV1,
|
|
dstReg: RegR30,
|
|
dstConst: 1,
|
|
vectorArrangement: VectorArrangementQ,
|
|
},
|
|
exp: []byte{0xc1, 0x13, 0x80, 0x3c},
|
|
},
|
|
{
|
|
name: "str q1, [x30, #0x100]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV1,
|
|
dstReg: RegR30,
|
|
dstConst: 0x100,
|
|
vectorArrangement: VectorArrangementQ,
|
|
},
|
|
exp: []byte{0xc1, 0x43, 0x80, 0x3d},
|
|
},
|
|
{
|
|
name: "stur q1, [x30, #0xfc]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV1,
|
|
dstReg: RegR30,
|
|
// This offset is not a multiple of 16 bytes, but fits in 9-bit signed integer,
|
|
// therefore it can be encoded as one instruction of "unscaled immediate".
|
|
dstConst: 0xfc,
|
|
vectorArrangement: VectorArrangementQ,
|
|
},
|
|
exp: []byte{0xc1, 0xc3, 0x8f, 0x3c},
|
|
},
|
|
{
|
|
name: `ldr w10, #0xc; str q11, [x12, x10]`,
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegV11,
|
|
dstReg: RegR12,
|
|
// This case offset is not a multiple of 16 bytes and doesn't fit in 9-bit signed integer,
|
|
// therefore, we encode the offset in a temporary register, then store it with the register offset variant.
|
|
dstConst: 0x108,
|
|
vectorArrangement: VectorArrangementQ,
|
|
},
|
|
exp: []byte{0x6a, 0x0, 0x0, 0x18, 0x8b, 0x69, 0xaa, 0x3c, 0x0, 0x0, 0x0, 0x14, 0x8, 0x1, 0x0, 0x0},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(RegR10)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeVectorRegisterToMemory(buf, tc.n)
|
|
require.NoError(t, err)
|
|
|
|
a.maybeFlushConstPool(buf, true)
|
|
|
|
err = a.Assemble(buf)
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_EncodeMemoryToVectorRegister(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
n *nodeImpl
|
|
exp []byte
|
|
}{
|
|
// ldr Register offset cases.
|
|
{
|
|
name: "ldr b11, [x12, x8]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegR12,
|
|
srcReg2: RegR8,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangementB,
|
|
},
|
|
exp: []byte{0x8b, 0x69, 0x68, 0x3c},
|
|
},
|
|
{
|
|
name: "ldr h11, [x30, x0]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegR30,
|
|
srcReg2: RegR0,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangementH,
|
|
},
|
|
exp: []byte{0xcb, 0x6b, 0x60, 0x7c},
|
|
},
|
|
{
|
|
name: "ldr s11, [x0, x30]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegR0,
|
|
srcReg2: RegR30,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangementS,
|
|
},
|
|
exp: []byte{0xb, 0x68, 0x7e, 0xbc},
|
|
},
|
|
{
|
|
name: "ldr d11, [x15, x15]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegR15,
|
|
srcReg2: RegR15,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangementD,
|
|
},
|
|
exp: []byte{0xeb, 0x69, 0x6f, 0xfc},
|
|
},
|
|
{
|
|
name: "ldr q30, [x0, x0]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegR0,
|
|
srcReg2: RegR0,
|
|
dstReg: RegV30,
|
|
vectorArrangement: VectorArrangementQ,
|
|
},
|
|
exp: []byte{0x1e, 0x68, 0xe0, 0x3c},
|
|
},
|
|
// ldr Constant offset cases.
|
|
{
|
|
name: "ldr b11, [x12, #0x7b]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
srcReg: RegR12,
|
|
srcConst: 0x7b,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangementB,
|
|
},
|
|
exp: []byte{0x8b, 0xed, 0x41, 0x3d},
|
|
},
|
|
{
|
|
name: "str h11, [x12, w30, uxtw]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
dstReg: RegV11,
|
|
srcReg: RegR12,
|
|
vectorArrangement: VectorArrangementH,
|
|
},
|
|
exp: []byte{0x8b, 0x1, 0x40, 0x7d},
|
|
},
|
|
{
|
|
name: "ldr w10, #0xc ; ldr s11, [x12, x10]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
dstReg: RegV11,
|
|
srcReg: RegR12,
|
|
srcConst: 1 << 28,
|
|
vectorArrangement: VectorArrangementS,
|
|
},
|
|
exp: []byte{0x6a, 0x0, 0x0, 0x18, 0x8b, 0x69, 0x6a, 0xbc, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x10},
|
|
},
|
|
{
|
|
name: "ldr w10, #0xc ; ldr d11, [x12, x10]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
dstReg: RegV11,
|
|
srcReg: RegR12,
|
|
srcConst: 1<<29 + 4,
|
|
vectorArrangement: VectorArrangementD,
|
|
},
|
|
exp: []byte{0x6a, 0x0, 0x0, 0x18, 0x8b, 0x69, 0x6a, 0xfc, 0x0, 0x0, 0x0, 0x14, 0x4, 0x0, 0x0, 0x20},
|
|
},
|
|
{
|
|
name: "ldr w10, #0xc ; ldr q1, [x30, x10]",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
dstReg: RegV1,
|
|
srcReg: RegR30,
|
|
srcConst: 1<<17 + 4,
|
|
vectorArrangement: VectorArrangementQ,
|
|
},
|
|
exp: []byte{0x6a, 0x0, 0x0, 0x18, 0xc1, 0x6b, 0xea, 0x3c, 0x0, 0x0, 0x0, 0x14, 0x4, 0x0, 0x2, 0x0},
|
|
},
|
|
{
|
|
name: "ld1r {v11.8b}, [x12]",
|
|
n: &nodeImpl{
|
|
instruction: LD1R,
|
|
srcReg: RegR12,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangement8B,
|
|
},
|
|
exp: []byte{0x8b, 0xc1, 0x40, 0xd},
|
|
},
|
|
{
|
|
name: "ld1r {v11.16b}, [x12]",
|
|
n: &nodeImpl{
|
|
instruction: LD1R,
|
|
srcReg: RegR12,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x8b, 0xc1, 0x40, 0x4d},
|
|
},
|
|
{
|
|
name: "ld1r {v11.4h}, [x12]",
|
|
n: &nodeImpl{
|
|
instruction: LD1R,
|
|
srcReg: RegR12,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangement4H,
|
|
},
|
|
exp: []byte{0x8b, 0xc5, 0x40, 0xd},
|
|
},
|
|
{
|
|
name: "ld1r {v9.8h}, [x0]",
|
|
n: &nodeImpl{
|
|
instruction: LD1R,
|
|
srcReg: RegR0,
|
|
dstReg: RegV0,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x0, 0xc4, 0x40, 0x4d},
|
|
},
|
|
{
|
|
name: "ld1r {v11.2s}, [x12]",
|
|
n: &nodeImpl{
|
|
instruction: LD1R,
|
|
srcReg: RegR12,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x8b, 0xc9, 0x40, 0xd},
|
|
},
|
|
{
|
|
name: "ld1r {v0.4s}, [x0]",
|
|
n: &nodeImpl{
|
|
instruction: LD1R,
|
|
srcReg: RegR0,
|
|
dstReg: RegV0,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x0, 0xc8, 0x40, 0x4d},
|
|
},
|
|
{
|
|
name: "ld1r {v11.1d}, [x12]",
|
|
n: &nodeImpl{
|
|
instruction: LD1R,
|
|
srcReg: RegR12,
|
|
dstReg: RegV11,
|
|
vectorArrangement: VectorArrangement1D,
|
|
},
|
|
exp: []byte{0x8b, 0xcd, 0x40, 0xd},
|
|
},
|
|
{
|
|
name: "ld1r {v0.2d}, [x0]",
|
|
n: &nodeImpl{
|
|
instruction: LD1R,
|
|
srcReg: RegR0,
|
|
dstReg: RegV0,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x0, 0xcc, 0x40, 0x4d},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(RegR10)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeMemoryToVectorRegister(buf, tc.n)
|
|
require.NoError(t, err)
|
|
|
|
a.maybeFlushConstPool(buf, true)
|
|
|
|
err = a.Assemble(buf)
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_EncodeVectorRegisterToVectorRegister(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
exp []byte
|
|
c asm.ConstantValue
|
|
inst asm.Instruction
|
|
x1 asm.Register
|
|
x2 asm.Register
|
|
arr VectorArrangement
|
|
srcIndex VectorIndex
|
|
dstIndex VectorIndex
|
|
}{
|
|
{
|
|
inst: XTN,
|
|
name: "xtn v10.2s, v2.2d",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement2D,
|
|
exp: []byte{0x4a, 0x28, 0xa1, 0xe},
|
|
},
|
|
{
|
|
inst: XTN,
|
|
name: "xtn v10.4h, v2.4s",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement4S,
|
|
exp: []byte{0x4a, 0x28, 0x61, 0xe},
|
|
},
|
|
{
|
|
inst: XTN,
|
|
name: "xtn v10.8b, v2.8h",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement8H,
|
|
exp: []byte{0x4a, 0x28, 0x21, 0xe},
|
|
},
|
|
{
|
|
inst: REV64,
|
|
name: "rev64 v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x8, 0x20, 0x4e},
|
|
},
|
|
{
|
|
inst: REV64,
|
|
name: "rev64 v10.4s, v2.4s",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement4S,
|
|
exp: []byte{0x4a, 0x8, 0xa0, 0x4e},
|
|
},
|
|
{
|
|
inst: VCNT,
|
|
name: "cnt v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x58, 0x20, 0x4e},
|
|
},
|
|
{
|
|
inst: VCNT,
|
|
name: "cnt v10.8b, v2.8b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement8B,
|
|
exp: []byte{0x4a, 0x58, 0x20, 0xe},
|
|
},
|
|
{
|
|
inst: VNEG,
|
|
name: "neg v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0xb8, 0x20, 0x6e},
|
|
},
|
|
{
|
|
inst: VNEG,
|
|
name: "neg v10.8h, v2.18h",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement8H,
|
|
exp: []byte{0x4a, 0xb8, 0x60, 0x6e},
|
|
},
|
|
{
|
|
inst: VNEG,
|
|
name: "neg v10.4s, v2.4s",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement4S,
|
|
exp: []byte{0x4a, 0xb8, 0xa0, 0x6e},
|
|
},
|
|
{
|
|
inst: VNEG,
|
|
name: "neg v10.2d, v2.2d",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement2D,
|
|
exp: []byte{0x4a, 0xb8, 0xe0, 0x6e},
|
|
},
|
|
{
|
|
inst: VABS,
|
|
name: "abs v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0xb8, 0x20, 0x4e},
|
|
},
|
|
{
|
|
inst: VABS,
|
|
name: "abs v10.8h, v2.18h",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement8H,
|
|
exp: []byte{0x4a, 0xb8, 0x60, 0x4e},
|
|
},
|
|
{
|
|
inst: VABS,
|
|
name: "abs v10.4s, v2.4s",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement4S,
|
|
exp: []byte{0x4a, 0xb8, 0xa0, 0x4e},
|
|
},
|
|
{
|
|
inst: VABS,
|
|
name: "abs v10.2d, v2.2d",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement2D,
|
|
exp: []byte{0x4a, 0xb8, 0xe0, 0x4e},
|
|
},
|
|
{
|
|
inst: ZIP1,
|
|
name: "zip1 v10.16b, v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x39, 0x2, 0x4e},
|
|
},
|
|
{
|
|
inst: ADDV,
|
|
name: "addv b10, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0xb8, 0x31, 0x4e},
|
|
},
|
|
{
|
|
inst: VORR,
|
|
name: "orr v10.16b, v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x1d, 0xa2, 0x4e},
|
|
},
|
|
{
|
|
inst: VORR,
|
|
name: "orr v10.8b, v10.8b, v2.8b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
arr: VectorArrangement8B,
|
|
exp: []byte{0x4a, 0x1d, 0xa2, 0xe},
|
|
},
|
|
{
|
|
name: "fadd v10.2d, v10.2d, v2.2d",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: VFADDD,
|
|
arr: VectorArrangement2D,
|
|
exp: []byte{0x4a, 0xd5, 0x62, 0x4e},
|
|
},
|
|
{
|
|
name: "fadd v10.4s, v10.4s, v2.4s",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: VFADDS,
|
|
arr: VectorArrangement4S,
|
|
exp: []byte{0x4a, 0xd5, 0x22, 0x4e},
|
|
},
|
|
{
|
|
name: "fsub v10.2d, v10.2d, v2.2d",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: VFSUBD,
|
|
arr: VectorArrangement2D,
|
|
exp: []byte{0x4a, 0xd5, 0xe2, 0x4e},
|
|
},
|
|
{
|
|
name: "fsub v10.4s, v10.4s, v2.4s",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: VFSUBS,
|
|
arr: VectorArrangement4S,
|
|
exp: []byte{0x4a, 0xd5, 0xa2, 0x4e},
|
|
},
|
|
{
|
|
name: "ushll v10.8h, v2.8b, #0",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: USHLL,
|
|
exp: []byte{0x4a, 0xa4, 0x8, 0x2f},
|
|
arr: VectorArrangement8B,
|
|
},
|
|
{
|
|
name: "ushll v10.8h, v2.8b, #7",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: USHLL,
|
|
exp: []byte{0x4a, 0xa4, 0xf, 0x2f},
|
|
arr: VectorArrangement8B,
|
|
c: 7,
|
|
},
|
|
{
|
|
name: "10.8h, v2.8b, #0",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x8, 0x4f},
|
|
arr: VectorArrangement16B,
|
|
c: 8,
|
|
},
|
|
{
|
|
name: "sshr v10.16b, v2.16b, #3",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0xd, 0x4f},
|
|
arr: VectorArrangement16B,
|
|
c: 3,
|
|
},
|
|
{
|
|
name: "sshr v10.16b, v2.16b, #1",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0xf, 0x4f},
|
|
arr: VectorArrangement16B,
|
|
c: 1,
|
|
},
|
|
{
|
|
name: "sshr v10.8b, v2.8b, #3",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0xd, 0xf},
|
|
arr: VectorArrangement8B,
|
|
c: 3,
|
|
},
|
|
{
|
|
name: "sshr v10.8h, v2.8h, #0x10",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x10, 0x4f},
|
|
arr: VectorArrangement8H,
|
|
c: 16,
|
|
},
|
|
{
|
|
name: "sshr v10.8h, v2.8h, #0xf",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x11, 0x4f},
|
|
arr: VectorArrangement8H,
|
|
c: 15,
|
|
},
|
|
{
|
|
name: "sshr v10.8h, v2.8h, #3",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x1d, 0x4f},
|
|
arr: VectorArrangement8H,
|
|
c: 3,
|
|
},
|
|
{
|
|
name: "sshr v10.4h, v2.4h, #0xf",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x11, 0xf},
|
|
arr: VectorArrangement4H,
|
|
c: 15,
|
|
},
|
|
{
|
|
name: "sshr v10.2s, v2.2s, #0x20",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x20, 0xf},
|
|
arr: VectorArrangement2S,
|
|
c: 32,
|
|
},
|
|
{
|
|
name: "sshr v10.2s, v2.2s, #0x1f",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x21, 0xf},
|
|
arr: VectorArrangement2S,
|
|
c: 31,
|
|
},
|
|
{
|
|
name: "sshr v10.2s, v2.2s, #7",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x39, 0xf},
|
|
arr: VectorArrangement2S,
|
|
c: 7,
|
|
},
|
|
{
|
|
name: "sshr v10.4s, v2.4s, #7",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x39, 0x4f},
|
|
arr: VectorArrangement4S,
|
|
c: 7,
|
|
},
|
|
{
|
|
name: "sshr v10.2d, v2.2d, #0x3f",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x41, 0x4f},
|
|
arr: VectorArrangement2D,
|
|
c: 63,
|
|
},
|
|
{
|
|
name: "sshr v10.2d, v2.2d, #0x21",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x5f, 0x4f},
|
|
arr: VectorArrangement2D,
|
|
c: 33,
|
|
},
|
|
{
|
|
name: "sshr v10.2d, v2.2d, #1",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHR,
|
|
exp: []byte{0x4a, 0x4, 0x7f, 0x4f},
|
|
arr: VectorArrangement2D,
|
|
c: 1,
|
|
},
|
|
{
|
|
name: "sshll v10.8h, v2.8b, #7",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHLL, exp: []byte{0x4a, 0xa4, 0xf, 0xf},
|
|
arr: VectorArrangement8B,
|
|
c: 7,
|
|
},
|
|
{
|
|
name: "sshll v10.4s, v2.4h, #0",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHLL,
|
|
exp: []byte{0x4a, 0xa4, 0x10, 0xf},
|
|
arr: VectorArrangement4H,
|
|
},
|
|
{
|
|
name: "sshll v10.4s, v2.4h, #0xf",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHLL,
|
|
exp: []byte{0x4a, 0xa4, 0x1f, 0xf},
|
|
arr: VectorArrangement4H,
|
|
c: 15,
|
|
},
|
|
{
|
|
name: "sshll v10.2d, v2.2s, #0",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHLL,
|
|
exp: []byte{0x4a, 0xa4, 0x20, 0xf},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
name: "sshll v10.2d, v2.2s, #0x1f",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHLL,
|
|
exp: []byte{0x4a, 0xa4, 0x3f, 0xf},
|
|
arr: VectorArrangement2S,
|
|
c: 31,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "ins v10.s[2], v2.s[1]",
|
|
inst: INSELEM,
|
|
exp: []byte{0x4a, 0x24, 0x14, 0x6e},
|
|
arr: VectorArrangementS,
|
|
srcIndex: 1,
|
|
dstIndex: 2,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "ins v10.s[0], v2.s[3]",
|
|
inst: INSELEM,
|
|
exp: []byte{0x4a, 0x64, 0x4, 0x6e},
|
|
arr: VectorArrangementS,
|
|
srcIndex: 3,
|
|
dstIndex: 0,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "ins v10.b[0], v2.b[0xf]",
|
|
inst: INSELEM,
|
|
exp: []byte{0x4a, 0x7c, 0x1, 0x6e},
|
|
arr: VectorArrangementB,
|
|
srcIndex: 15,
|
|
dstIndex: 0,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "ins v10.d[1], v2.d[0]",
|
|
inst: INSELEM,
|
|
exp: []byte{0x4a, 0x4, 0x18, 0x6e},
|
|
arr: VectorArrangementD,
|
|
srcIndex: 0,
|
|
dstIndex: 1,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "dup v10.2d, v2.d[0]",
|
|
inst: DUPELEM,
|
|
exp: []byte{0x4a, 0x4, 0x8, 0x4e},
|
|
arr: VectorArrangementD,
|
|
srcIndex: 0,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "dup v10.2d, v2.d[1]",
|
|
inst: DUPELEM,
|
|
exp: []byte{0x4a, 0x4, 0x18, 0x4e},
|
|
arr: VectorArrangementD,
|
|
srcIndex: 1,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "dup v10.4s, v2.s[3]",
|
|
inst: DUPELEM,
|
|
exp: []byte{0x4a, 0x4, 0x1c, 0x4e},
|
|
arr: VectorArrangementS,
|
|
srcIndex: 3,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "dup v10.8h, v2.h[7]",
|
|
inst: DUPELEM,
|
|
exp: []byte{0x4a, 0x4, 0x1e, 0x4e},
|
|
arr: VectorArrangementH,
|
|
srcIndex: 7,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "dup v10.16b, v2.b[0xf]",
|
|
inst: DUPELEM,
|
|
exp: []byte{0x4a, 0x4, 0x1f, 0x4e},
|
|
arr: VectorArrangementB,
|
|
srcIndex: 15,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "umaxp v10.16b, v10.16b, v2.16b",
|
|
inst: UMAXP,
|
|
exp: []byte{0x4a, 0xa5, 0x22, 0x6e},
|
|
arr: VectorArrangement16B,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "umaxp v10.8h, v10.8h, v2.8h",
|
|
inst: UMAXP,
|
|
exp: []byte{0x4a, 0xa5, 0x62, 0x6e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "umaxp v10.4s, v10.4s, v2.4s",
|
|
inst: UMAXP,
|
|
exp: []byte{0x4a, 0xa5, 0xa2, 0x6e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV11,
|
|
x2: RegV11,
|
|
name: "addp d11, v11.2d",
|
|
inst: ADDP,
|
|
arr: VectorArrangement2D,
|
|
exp: []byte{0x6b, 0xb9, 0xf1, 0x5e},
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "addp v10.16b, v10.16b, v2.16b",
|
|
inst: VADDP,
|
|
exp: []byte{0x4a, 0xbd, 0x22, 0x4e},
|
|
arr: VectorArrangement16B,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "addp v10.8h, v10.8h, v2.8h",
|
|
inst: VADDP,
|
|
exp: []byte{0x4a, 0xbd, 0x62, 0x4e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "addp v10.4s, v10.4s, v2.4s",
|
|
inst: VADDP,
|
|
exp: []byte{0x4a, 0xbd, 0xa2, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "uminv b10, v2.16b",
|
|
inst: UMINV,
|
|
exp: []byte{0x4a, 0xa8, 0x31, 0x6e},
|
|
arr: VectorArrangement16B,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "uminv h10, v2.8h",
|
|
inst: UMINV,
|
|
exp: []byte{0x4a, 0xa8, 0x71, 0x6e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "uminv s10, v2.4s",
|
|
inst: UMINV,
|
|
exp: []byte{0x4a, 0xa8, 0xb1, 0x6e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "cmeq v10.2d, v10.2d, v2.2d",
|
|
arr: VectorArrangement2D,
|
|
inst: CMEQ,
|
|
exp: []byte{0x4a, 0x8d, 0xe2, 0x6e},
|
|
},
|
|
{
|
|
x1: RegRZR,
|
|
x2: RegV12,
|
|
name: "cmeq v12.2d, v12.2d, #0",
|
|
inst: CMEQZERO,
|
|
arr: VectorArrangement2D,
|
|
exp: []byte{0x8c, 0x99, 0xe0, 0x4e},
|
|
},
|
|
{
|
|
name: "tbl v1.8b, {v0.16b}, v1.8b",
|
|
x1: RegV0,
|
|
x2: RegV1,
|
|
inst: TBL1,
|
|
arr: VectorArrangement8B,
|
|
exp: []byte{0x1, 0x0, 0x1, 0xe},
|
|
},
|
|
{
|
|
name: "tbl v1.16b, {v0.16b}, v1.16b",
|
|
x1: RegV0,
|
|
x2: RegV1,
|
|
inst: TBL1,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x1, 0x0, 0x1, 0x4e},
|
|
},
|
|
{
|
|
name: "tbl v30.8b, {v0.16b, v1.16b}, v30.8b",
|
|
x1: RegV0,
|
|
x2: RegV30,
|
|
inst: TBL2,
|
|
arr: VectorArrangement8B,
|
|
exp: []byte{0x1e, 0x20, 0x1e, 0xe},
|
|
},
|
|
{
|
|
name: "tbl v1.16b, {v31.16b, v0.16b}, v1.16b",
|
|
x1: RegV31,
|
|
x2: RegV1,
|
|
inst: TBL2,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0xe1, 0x23, 0x1, 0x4e},
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "add v10.4s, v10.4s, v2.4s",
|
|
inst: VADD,
|
|
exp: []byte{0x4a, 0x85, 0xa2, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "add v10.2d, v10.2d, v2.2d",
|
|
inst: VADD,
|
|
exp: []byte{0x4a, 0x85, 0xe2, 0x4e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "sub v10.8h, v10.8h, v2.8h",
|
|
inst: VSUB,
|
|
exp: []byte{0x4a, 0x85, 0x62, 0x6e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
x1: RegV29,
|
|
x2: RegV30,
|
|
name: "sub v30.16b, v30.16b, v29.16b",
|
|
inst: VSUB,
|
|
exp: []byte{0xde, 0x87, 0x3d, 0x6e},
|
|
arr: VectorArrangement16B,
|
|
},
|
|
{
|
|
name: "bic v10.16b, v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: BIC,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x1d, 0x62, 0x4e},
|
|
},
|
|
{
|
|
name: "eor v10.16b, v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: EOR,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x1d, 0x22, 0x6e},
|
|
},
|
|
{
|
|
name: "bsl v10.16b, v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: BSL,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x1d, 0x62, 0x6e},
|
|
},
|
|
{
|
|
name: "bsl v10.16b, v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: BSL,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x1d, 0x62, 0x6e},
|
|
},
|
|
{
|
|
name: "and v10.16b, v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: VAND,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x1d, 0x22, 0x4e},
|
|
},
|
|
{
|
|
// mvn is an alias of NOT: https://developer.arm.com/documentation/ddi0596/2020-12/SIMD-FP-Instructions/MVN--Bitwise-NOT--vector---an-alias-of-NOT-?lang=en
|
|
name: "mvn v10.16b, v2.16b",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: NOT,
|
|
arr: VectorArrangement16B,
|
|
exp: []byte{0x4a, 0x58, 0x20, 0x6e},
|
|
},
|
|
{
|
|
name: "fneg v10.2d, v2.2d",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: VFNEG,
|
|
arr: VectorArrangement2D,
|
|
exp: []byte{0x4a, 0xf8, 0xe0, 0x6e},
|
|
},
|
|
{
|
|
name: "fneg v10.4s, v2.4s",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: VFNEG,
|
|
arr: VectorArrangement4S,
|
|
exp: []byte{0x4a, 0xf8, 0xa0, 0x6e},
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "sshl v10.2d, v10.2d, v2.2d",
|
|
inst: SSHL,
|
|
exp: []byte{0x4a, 0x45, 0xe2, 0x4e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sshl v30.4s, v30.4s, v25.4s",
|
|
inst: SSHL,
|
|
exp: []byte{0xde, 0x47, 0xb9, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
name: "ushl v10.8h, v10.8h, v2.8h",
|
|
inst: USHL,
|
|
exp: []byte{0x4a, 0x45, 0x62, 0x6e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "ushl v30.16b, v30.16b, v25.16b",
|
|
inst: USHL,
|
|
exp: []byte{0xde, 0x47, 0x39, 0x6e},
|
|
arr: VectorArrangement16B,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fabs v30.4s, v25.4s",
|
|
inst: VFABS,
|
|
exp: []byte{0x3e, 0xfb, 0xa0, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fabs v30.2s, v25.2s",
|
|
inst: VFABS,
|
|
exp: []byte{0x3e, 0xfb, 0xa0, 0xe},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fabs v30.2d, v25.2d",
|
|
inst: VFABS,
|
|
exp: []byte{0x3e, 0xfb, 0xe0, 0x4e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fsqrt v30.4s, v25.4s",
|
|
inst: VFSQRT,
|
|
exp: []byte{0x3e, 0xfb, 0xa1, 0x6e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fsqrt v30.2s, v25.2s",
|
|
inst: VFSQRT,
|
|
exp: []byte{0x3e, 0xfb, 0xa1, 0x2e},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fsqrt v30.2d, v25.2d",
|
|
inst: VFSQRT,
|
|
exp: []byte{0x3e, 0xfb, 0xe1, 0x6e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintm v30.4s, v25.4s",
|
|
inst: VFRINTM,
|
|
exp: []byte{0x3e, 0x9b, 0x21, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintm v30.2s, v25.2s",
|
|
inst: VFRINTM,
|
|
exp: []byte{0x3e, 0x9b, 0x21, 0xe},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintm v30.2d, v25.2d",
|
|
inst: VFRINTM,
|
|
exp: []byte{0x3e, 0x9b, 0x61, 0x4e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintn v30.4s, v25.4s",
|
|
inst: VFRINTN,
|
|
exp: []byte{0x3e, 0x8b, 0x21, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintn v30.2s, v25.2s",
|
|
inst: VFRINTN,
|
|
exp: []byte{0x3e, 0x8b, 0x21, 0xe},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintn v30.2d, v25.2d",
|
|
inst: VFRINTN,
|
|
exp: []byte{0x3e, 0x8b, 0x61, 0x4e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintp v30.4s, v25.4s",
|
|
inst: VFRINTP,
|
|
exp: []byte{0x3e, 0x8b, 0xa1, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintp v30.2s, v25.2s",
|
|
inst: VFRINTP,
|
|
exp: []byte{0x3e, 0x8b, 0xa1, 0xe},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintp v30.2d, v25.2d",
|
|
inst: VFRINTP,
|
|
exp: []byte{0x3e, 0x8b, 0xe1, 0x4e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintp v30.4s, v25.4s",
|
|
inst: VFRINTN,
|
|
exp: []byte{0x3e, 0x8b, 0x21, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintp v30.2s, v25.2s",
|
|
inst: VFRINTN,
|
|
exp: []byte{0x3e, 0x8b, 0x21, 0xe},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "frintp v30.2d, v25.2d",
|
|
inst: VFRINTN,
|
|
exp: []byte{0x3e, 0x8b, 0x61, 0x4e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "shll v30.8h, v25.8b, #8",
|
|
inst: SHLL,
|
|
exp: []byte{0x3e, 0x3b, 0x21, 0x2e},
|
|
arr: VectorArrangement8B,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "shll v30.4s, v25.4h, #16",
|
|
inst: SHLL,
|
|
exp: []byte{0x3e, 0x3b, 0x61, 0x2e},
|
|
arr: VectorArrangement4H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "shll v30.2d, v25.2s, #32",
|
|
inst: SHLL,
|
|
exp: []byte{0x3e, 0x3b, 0xa1, 0x2e},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "uaddlv h30, v25.16b",
|
|
inst: UADDLV,
|
|
exp: []byte{0x3e, 0x3b, 0x30, 0x6e},
|
|
arr: VectorArrangement16B,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "uaddlv s30, v25.8h",
|
|
inst: UADDLV,
|
|
exp: []byte{0x3e, 0x3b, 0x70, 0x6e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "uaddlv d30, v25.4s",
|
|
inst: UADDLV,
|
|
exp: []byte{0x3e, 0x3b, 0xb0, 0x6e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "saddlp v30.2d, v25.4s",
|
|
inst: SADDLP,
|
|
exp: []byte{0x3e, 0x2b, 0xa0, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "saddlp v30.4s, v25.8h",
|
|
inst: SADDLP,
|
|
exp: []byte{0x3e, 0x2b, 0x60, 0x4e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "uaddlp v30.2d, v25.4s",
|
|
inst: UADDLP,
|
|
exp: []byte{0x3e, 0x2b, 0xa0, 0x6e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "uaddlp v30.4s, v25.8h",
|
|
inst: UADDLP,
|
|
exp: []byte{0x3e, 0x2b, 0x60, 0x6e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
name: "sshll2 v10.8h, v2.16b, #7",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHLL2,
|
|
exp: []byte{0x4a, 0xa4, 0xf, 0x4f},
|
|
arr: VectorArrangement16B,
|
|
c: 7,
|
|
},
|
|
{
|
|
name: "sshll2 v10.4s, v2.8h, #0",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHLL2,
|
|
exp: []byte{0x4a, 0xa4, 0x10, 0x4f},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
name: "sshll2 v10.2d, v2.4s, #0x15",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: SSHLL2,
|
|
exp: []byte{0x4a, 0xa4, 0x35, 0x4f},
|
|
arr: VectorArrangement4S,
|
|
c: 21,
|
|
},
|
|
{
|
|
name: "ushll2 v10.8h, v2.16b, #7",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: USHLL2,
|
|
exp: []byte{0x4a, 0xa4, 0xf, 0x6f},
|
|
arr: VectorArrangement16B,
|
|
c: 7,
|
|
},
|
|
{
|
|
name: "ushll2 v10.4s, v2.8h, #0",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: USHLL2,
|
|
exp: []byte{0x4a, 0xa4, 0x10, 0x6f},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
name: "ushll2 v10.2d, v2.4s, #0x15",
|
|
x1: RegV2,
|
|
x2: RegV10,
|
|
inst: USHLL2,
|
|
exp: []byte{0x4a, 0xa4, 0x35, 0x6f},
|
|
arr: VectorArrangement4S,
|
|
c: 21,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtzs v30.4s, v25.4s",
|
|
inst: VFCVTZS,
|
|
exp: []byte{0x3e, 0xbb, 0xa1, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtzs v30.2s, v25.2s",
|
|
inst: VFCVTZS,
|
|
exp: []byte{0x3e, 0xbb, 0xa1, 0xe},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtzs v30.2d, v25.2d",
|
|
inst: VFCVTZS,
|
|
exp: []byte{0x3e, 0xbb, 0xe1, 0x4e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtzu v30.4s, v25.4s",
|
|
inst: VFCVTZU,
|
|
exp: []byte{0x3e, 0xbb, 0xa1, 0x6e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtzu v30.2s, v25.2s",
|
|
inst: VFCVTZU,
|
|
exp: []byte{0x3e, 0xbb, 0xa1, 0x2e},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtzu v30.2d, v25.2d",
|
|
inst: VFCVTZU,
|
|
exp: []byte{0x3e, 0xbb, 0xe1, 0x6e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtn v30.2s, v25.2d",
|
|
inst: SQXTN,
|
|
exp: []byte{0x3e, 0x4b, 0xa1, 0xe},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtn v30.4h, v25.4s",
|
|
inst: SQXTN,
|
|
exp: []byte{0x3e, 0x4b, 0x61, 0xe},
|
|
arr: VectorArrangement4H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "uqxtn v30.2s, v25.2d",
|
|
inst: UQXTN,
|
|
exp: []byte{0x3e, 0x4b, 0xa1, 0x2e},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "uqxtn v30.4h, v25.4s",
|
|
inst: UQXTN,
|
|
exp: []byte{0x3e, 0x4b, 0x61, 0x2e},
|
|
arr: VectorArrangement4H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtn2 v30.16b, v25.8h",
|
|
inst: SQXTN2,
|
|
exp: []byte{0x3e, 0x4b, 0x21, 0x4e},
|
|
arr: VectorArrangement16B,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtn2 v30.8h, v25.4s",
|
|
inst: SQXTN2,
|
|
exp: []byte{0x3e, 0x4b, 0x61, 0x4e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtn2 v30.4s, v25.2d",
|
|
inst: SQXTN2,
|
|
exp: []byte{0x3e, 0x4b, 0xa1, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtun v30.8b, v25.8h",
|
|
inst: SQXTUN,
|
|
exp: []byte{0x3e, 0x2b, 0x21, 0x2e},
|
|
arr: VectorArrangement8B,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtun v30.4h, v25.4s",
|
|
inst: SQXTUN,
|
|
exp: []byte{0x3e, 0x2b, 0x61, 0x2e},
|
|
arr: VectorArrangement4H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtun v30.2s, v25.2d",
|
|
inst: SQXTUN,
|
|
exp: []byte{0x3e, 0x2b, 0xa1, 0x2e},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtun2 v30.16b, v25.8h",
|
|
inst: SQXTUN2,
|
|
exp: []byte{0x3e, 0x2b, 0x21, 0x6e},
|
|
arr: VectorArrangement16B,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtun2 v30.8h, v25.4s",
|
|
inst: SQXTUN2,
|
|
exp: []byte{0x3e, 0x2b, 0x61, 0x6e},
|
|
arr: VectorArrangement8H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "sqxtun2 v30.4s, v25.2d",
|
|
inst: SQXTUN2,
|
|
exp: []byte{0x3e, 0x2b, 0xa1, 0x6e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "scvtf v30.2d, v25.2d",
|
|
inst: VSCVTF,
|
|
exp: []byte{0x3e, 0xdb, 0x61, 0x4e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "scvtf v30.4s, v25.4s",
|
|
inst: VSCVTF,
|
|
exp: []byte{0x3e, 0xdb, 0x21, 0x4e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "ucvtf v30.2d, v25.2d",
|
|
inst: VUCVTF,
|
|
exp: []byte{0x3e, 0xdb, 0x61, 0x6e},
|
|
arr: VectorArrangement2D,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "ucvtf v30.4s, v25.4s",
|
|
inst: VUCVTF,
|
|
exp: []byte{0x3e, 0xdb, 0x21, 0x6e},
|
|
arr: VectorArrangement4S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtl v30.2d, v25.2s",
|
|
inst: FCVTL,
|
|
exp: []byte{0x3e, 0x7b, 0x61, 0xe},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtl v30.4s, v25.4h",
|
|
inst: FCVTL,
|
|
exp: []byte{0x3e, 0x7b, 0x21, 0xe},
|
|
arr: VectorArrangement4H,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtn v30.2s, v25.2d",
|
|
inst: FCVTN,
|
|
exp: []byte{0x3e, 0x6b, 0x61, 0xe},
|
|
arr: VectorArrangement2S,
|
|
},
|
|
{
|
|
x1: RegV25,
|
|
x2: RegV30,
|
|
name: "fcvtn v30.4h, v25.4s",
|
|
inst: FCVTN,
|
|
exp: []byte{0x3e, 0x6b, 0x21, 0xe},
|
|
arr: VectorArrangement4H,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeVectorRegisterToVectorRegister(buf, &nodeImpl{
|
|
instruction: tc.inst,
|
|
srcReg: tc.x1,
|
|
srcConst: tc.c,
|
|
dstReg: tc.x2,
|
|
vectorArrangement: tc.arr,
|
|
srcVectorIndex: tc.srcIndex,
|
|
dstVectorIndex: tc.dstIndex,
|
|
})
|
|
require.NoError(t, err)
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_EncodeVectorRegisterToRegister(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
n *nodeImpl
|
|
exp []byte
|
|
}{
|
|
{
|
|
name: "umov w10, v0.b[0xf]",
|
|
n: &nodeImpl{
|
|
instruction: UMOV,
|
|
srcReg: RegV0,
|
|
dstReg: RegR10,
|
|
vectorArrangement: VectorArrangementB,
|
|
srcVectorIndex: 15,
|
|
},
|
|
exp: []byte{0xa, 0x3c, 0x1f, 0xe},
|
|
},
|
|
{
|
|
name: "mov w10, v0.s[3]",
|
|
n: &nodeImpl{
|
|
instruction: UMOV,
|
|
srcReg: RegV0,
|
|
dstReg: RegR10,
|
|
vectorArrangement: VectorArrangementS,
|
|
srcVectorIndex: 3,
|
|
},
|
|
exp: []byte{0xa, 0x3c, 0x1c, 0xe},
|
|
},
|
|
{
|
|
name: "mov x5, v30.d[1]",
|
|
n: &nodeImpl{
|
|
instruction: UMOV,
|
|
srcReg: RegV30,
|
|
dstReg: RegR5,
|
|
vectorArrangement: VectorArrangementD,
|
|
srcVectorIndex: 1,
|
|
},
|
|
exp: []byte{0xc5, 0x3f, 0x18, 0x4e},
|
|
},
|
|
{
|
|
name: "smov w10, v0.b[0xf]",
|
|
n: &nodeImpl{
|
|
instruction: SMOV32,
|
|
srcReg: RegV0,
|
|
dstReg: RegR10,
|
|
vectorArrangement: VectorArrangementB,
|
|
srcVectorIndex: 15,
|
|
},
|
|
exp: []byte{0xa, 0x2c, 0x1f, 0xe},
|
|
},
|
|
{
|
|
name: "smov w10, v0.b[0]",
|
|
n: &nodeImpl{
|
|
instruction: SMOV32,
|
|
srcReg: RegV0,
|
|
dstReg: RegR10,
|
|
vectorArrangement: VectorArrangementB,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xa, 0x2c, 0x1, 0xe},
|
|
},
|
|
{
|
|
name: "smov w1, v30.h[7]",
|
|
n: &nodeImpl{
|
|
instruction: SMOV32,
|
|
srcReg: RegV30,
|
|
dstReg: RegR1,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 7,
|
|
},
|
|
exp: []byte{0xc1, 0x2f, 0x1e, 0xe},
|
|
},
|
|
{
|
|
name: "smov w1, v30.h[0]",
|
|
n: &nodeImpl{
|
|
instruction: SMOV32,
|
|
srcReg: RegV30,
|
|
dstReg: RegR1,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xc1, 0x2f, 0x2, 0xe},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeVectorRegisterToRegister(buf, tc.n)
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_EncodeLeftShiftedRegisterToRegister(t *testing.T) {
|
|
t.Run("error", func(t *testing.T) {
|
|
tests := []struct {
|
|
n *nodeImpl
|
|
expErr string
|
|
}{
|
|
{
|
|
n: &nodeImpl{
|
|
instruction: SUB, types: operandTypesLeftShiftedRegisterToRegister,
|
|
srcReg: RegR0, srcReg2: RegR0, dstReg: RegR0,
|
|
},
|
|
expErr: "SUB is unsupported for LeftShiftedRegisterToRegister type",
|
|
},
|
|
{
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcConst: -1, srcReg: RegR0, srcReg2: RegR0, dstReg: RegR0,
|
|
},
|
|
expErr: "shift amount must fit in unsigned 6-bit integer (0-64) but got -1",
|
|
},
|
|
{
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcConst: -1, srcReg: RegV0, srcReg2: RegR0, dstReg: RegR0,
|
|
},
|
|
expErr: "V0 is not integer",
|
|
},
|
|
{
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcConst: -1, srcReg: RegR0, srcReg2: RegV0, dstReg: RegR0,
|
|
},
|
|
expErr: "V0 is not integer",
|
|
},
|
|
{
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcConst: -1, srcReg: RegR0, srcReg2: RegR0, dstReg: RegV0,
|
|
},
|
|
expErr: "V0 is not integer",
|
|
},
|
|
}
|
|
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeLeftShiftedRegisterToRegister(buf, tc.n)
|
|
require.EqualError(t, err, tc.expErr)
|
|
}
|
|
})
|
|
|
|
tests := []struct {
|
|
name string
|
|
n *nodeImpl
|
|
exp []byte
|
|
}{
|
|
{
|
|
name: "ADD",
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcReg: RegR0,
|
|
srcReg2: RegR29,
|
|
srcConst: 1,
|
|
dstReg: RegR21,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0x15, 0x4, 0x1d, 0x8b},
|
|
},
|
|
{
|
|
name: "ADD",
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcReg: RegR0,
|
|
srcReg2: RegR29,
|
|
srcConst: 2,
|
|
dstReg: RegR21,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0x15, 0x8, 0x1d, 0x8b},
|
|
},
|
|
{
|
|
name: "ADD",
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcReg: RegR0,
|
|
srcReg2: RegR29,
|
|
srcConst: 8,
|
|
dstReg: RegR21,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0x15, 0x20, 0x1d, 0x8b},
|
|
},
|
|
{
|
|
name: "ADD",
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcReg: RegR29,
|
|
srcReg2: RegR0,
|
|
srcConst: 16,
|
|
dstReg: RegR21,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xb5, 0x43, 0x0, 0x8b},
|
|
},
|
|
{
|
|
name: "ADD",
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcReg: RegR29,
|
|
srcReg2: RegR0,
|
|
srcConst: 64,
|
|
dstReg: RegR21,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xb5, 0x3, 0x0, 0x8b},
|
|
},
|
|
{
|
|
name: "ADD",
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcReg: RegRZR,
|
|
srcReg2: RegR0,
|
|
srcConst: 64,
|
|
dstReg: RegR21,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xf5, 0x3, 0x0, 0x8b},
|
|
},
|
|
{
|
|
name: "ADD",
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcReg: RegRZR,
|
|
srcReg2: RegRZR,
|
|
srcConst: 64,
|
|
dstReg: RegR21,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xf5, 0x3, 0x1f, 0x8b},
|
|
},
|
|
{
|
|
name: "ADD",
|
|
n: &nodeImpl{
|
|
instruction: ADD,
|
|
srcReg: RegRZR,
|
|
srcReg2: RegRZR,
|
|
srcConst: 64,
|
|
dstReg: RegRZR,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xff, 0x3, 0x1f, 0x8b},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeLeftShiftedRegisterToRegister(buf, tc.n)
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_encodeTwoRegistersToNone(t *testing.T) {
|
|
t.Run("error", func(t *testing.T) {
|
|
tests := []struct {
|
|
n *nodeImpl
|
|
expErr string
|
|
}{
|
|
{
|
|
n: &nodeImpl{
|
|
instruction: SUB, types: operandTypesTwoRegistersToNone,
|
|
srcReg: RegR0, srcReg2: RegR0, dstReg: RegR0,
|
|
},
|
|
expErr: "SUB is unsupported for TwoRegistersToNone type",
|
|
},
|
|
{
|
|
n: &nodeImpl{
|
|
instruction: CMP,
|
|
srcReg: RegR0, srcReg2: RegV0,
|
|
},
|
|
expErr: "V0 is not integer",
|
|
},
|
|
{
|
|
n: &nodeImpl{
|
|
instruction: FCMPS,
|
|
srcReg: RegR0, srcReg2: RegV0,
|
|
},
|
|
expErr: "R0 is not vector",
|
|
},
|
|
}
|
|
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeTwoRegistersToNone(buf, tc.n)
|
|
require.EqualError(t, err, tc.expErr)
|
|
}
|
|
})
|
|
|
|
tests := []struct {
|
|
name string
|
|
n *nodeImpl
|
|
exp []byte
|
|
}{
|
|
{
|
|
name: "CMP",
|
|
n: &nodeImpl{
|
|
instruction: CMP,
|
|
srcReg: RegRZR,
|
|
srcReg2: RegRZR,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xff, 0x3, 0x1f, 0xeb},
|
|
},
|
|
{
|
|
name: "CMP",
|
|
n: &nodeImpl{
|
|
instruction: CMP,
|
|
srcReg: RegRZR,
|
|
srcReg2: RegR30,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xdf, 0x3, 0x1f, 0xeb},
|
|
},
|
|
{
|
|
name: "CMP",
|
|
n: &nodeImpl{
|
|
instruction: CMP,
|
|
srcReg: RegR30,
|
|
srcReg2: RegRZR,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xff, 0x3, 0x1e, 0xeb},
|
|
},
|
|
{
|
|
name: "CMP",
|
|
n: &nodeImpl{
|
|
instruction: CMP,
|
|
srcReg: RegR30,
|
|
srcReg2: RegR30,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xdf, 0x3, 0x1e, 0xeb},
|
|
},
|
|
{
|
|
name: "CMPW",
|
|
n: &nodeImpl{
|
|
instruction: CMPW,
|
|
srcReg: RegRZR,
|
|
srcReg2: RegRZR,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xff, 0x3, 0x1f, 0x6b},
|
|
},
|
|
{
|
|
name: "CMPW",
|
|
n: &nodeImpl{
|
|
instruction: CMPW,
|
|
srcReg: RegRZR,
|
|
srcReg2: RegR30,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xdf, 0x3, 0x1f, 0x6b},
|
|
},
|
|
{
|
|
name: "CMPW",
|
|
n: &nodeImpl{
|
|
instruction: CMPW,
|
|
srcReg: RegR30,
|
|
srcReg2: RegRZR,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xff, 0x3, 0x1e, 0x6b},
|
|
},
|
|
{
|
|
name: "CMPW",
|
|
n: &nodeImpl{
|
|
instruction: CMPW,
|
|
srcReg: RegR30,
|
|
srcReg2: RegR30,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xdf, 0x3, 0x1e, 0x6b},
|
|
},
|
|
{
|
|
name: "FCMPD",
|
|
n: &nodeImpl{
|
|
instruction: FCMPD,
|
|
srcReg: RegV0,
|
|
srcReg2: RegV0,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0x0, 0x20, 0x60, 0x1e},
|
|
},
|
|
{
|
|
name: "FCMPD",
|
|
n: &nodeImpl{
|
|
instruction: FCMPD,
|
|
srcReg: RegV0,
|
|
srcReg2: RegV31,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xe0, 0x23, 0x60, 0x1e},
|
|
},
|
|
{
|
|
name: "FCMPD",
|
|
n: &nodeImpl{
|
|
instruction: FCMPD,
|
|
srcReg: RegV31,
|
|
srcReg2: RegV0,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0x0, 0x20, 0x7f, 0x1e},
|
|
},
|
|
{
|
|
name: "FCMPD",
|
|
n: &nodeImpl{
|
|
instruction: FCMPD,
|
|
srcReg: RegV31,
|
|
srcReg2: RegV31,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xe0, 0x23, 0x7f, 0x1e},
|
|
},
|
|
{
|
|
name: "FCMPS",
|
|
n: &nodeImpl{
|
|
instruction: FCMPS,
|
|
srcReg: RegV0,
|
|
srcReg2: RegV0,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0x0, 0x20, 0x20, 0x1e},
|
|
},
|
|
{
|
|
name: "FCMPS",
|
|
n: &nodeImpl{
|
|
instruction: FCMPS,
|
|
srcReg: RegV0,
|
|
srcReg2: RegV31,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xe0, 0x23, 0x20, 0x1e},
|
|
},
|
|
{
|
|
name: "FCMPS",
|
|
n: &nodeImpl{
|
|
instruction: FCMPS,
|
|
srcReg: RegV31,
|
|
srcReg2: RegV0,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0x0, 0x20, 0x3f, 0x1e},
|
|
},
|
|
{
|
|
name: "FCMPS",
|
|
n: &nodeImpl{
|
|
instruction: FCMPS,
|
|
srcReg: RegV31,
|
|
srcReg2: RegV31,
|
|
vectorArrangement: VectorArrangementH,
|
|
srcVectorIndex: 0,
|
|
},
|
|
exp: []byte{0xe0, 0x23, 0x3f, 0x1e},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeTwoRegistersToNone(buf, tc.n)
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_EncodeThreeRegistersToRegister(t *testing.T) {
|
|
const src1, src2, src3, dst = RegR1, RegR10, RegR30, RegR11
|
|
|
|
tests := []struct {
|
|
name string
|
|
exp []byte
|
|
inst asm.Instruction
|
|
}{
|
|
{
|
|
name: "MSUB/src1=R1,src2=R10,src3=R30,dst=R11",
|
|
inst: MSUB,
|
|
exp: []byte{0xcb, 0xab, 0x1, 0x9b},
|
|
},
|
|
{
|
|
name: "MSUBW/src1=R1,src2=R10,src3=R30,dst=R11",
|
|
inst: MSUBW,
|
|
exp: []byte{0xcb, 0xab, 0x1, 0x1b},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeThreeRegistersToRegister(buf, &nodeImpl{
|
|
instruction: tc.inst, srcReg: src1, srcReg2: src2, dstReg: src3, dstReg2: dst,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual[:4])
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_encodeTwoVectorRegistersToVectorRegister(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
n *nodeImpl
|
|
exp []byte
|
|
}{
|
|
{
|
|
name: "orr v30.16b, v10.16b, v1.16b",
|
|
n: &nodeImpl{
|
|
instruction: VORR,
|
|
dstReg: RegV30,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV10,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x5e, 0x1d, 0xa1, 0x4e},
|
|
},
|
|
{
|
|
name: "orr v30.8b, v10.8b, v1.8b",
|
|
n: &nodeImpl{
|
|
instruction: VORR,
|
|
dstReg: RegV30,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV10,
|
|
vectorArrangement: VectorArrangement8B,
|
|
},
|
|
exp: []byte{0x5e, 0x1d, 0xa1, 0xe},
|
|
},
|
|
{
|
|
name: "bsl v0.8b, v15.8b, v1.8b",
|
|
n: &nodeImpl{
|
|
instruction: BSL,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
vectorArrangement: VectorArrangement8B,
|
|
},
|
|
exp: []byte{0xe0, 0x1d, 0x61, 0x2e},
|
|
},
|
|
{
|
|
name: "zip1 v0.4s, v15.4s, v1.4s",
|
|
n: &nodeImpl{
|
|
instruction: ZIP1,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0xe0, 0x39, 0x81, 0x4e},
|
|
},
|
|
{
|
|
name: "zip1 v0.2d, v15.2d, v1.2d",
|
|
n: &nodeImpl{
|
|
instruction: ZIP1,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0xe0, 0x39, 0xc1, 0x4e},
|
|
},
|
|
{
|
|
name: "ext v0.16b, v15.16b, v1.16b, #0xf",
|
|
n: &nodeImpl{
|
|
instruction: EXT,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
srcConst: 0xf,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0xe0, 0x79, 0x1, 0x6e},
|
|
},
|
|
{
|
|
name: "ext v0.16b, v15.16b, v1.16b, #8",
|
|
n: &nodeImpl{
|
|
instruction: EXT,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
srcConst: 8,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0xe0, 0x41, 0x1, 0x6e},
|
|
},
|
|
{
|
|
name: "ext v0.16b, v15.16b, v1.16b, #0",
|
|
n: &nodeImpl{
|
|
instruction: EXT,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
srcConst: 0,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0xe0, 0x1, 0x1, 0x6e},
|
|
},
|
|
{
|
|
name: "ext v0.8b, v15.8b, v1.8b, #7",
|
|
n: &nodeImpl{
|
|
instruction: EXT,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
srcConst: 7,
|
|
vectorArrangement: VectorArrangement8B,
|
|
},
|
|
exp: []byte{0xe0, 0x39, 0x1, 0x2e},
|
|
},
|
|
{
|
|
name: "cmeq v0.8b, v15.8b, v1.8b",
|
|
n: &nodeImpl{
|
|
instruction: CMEQ,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
vectorArrangement: VectorArrangement8B,
|
|
},
|
|
exp: []byte{0xe0, 0x8d, 0x21, 0x2e},
|
|
},
|
|
{
|
|
name: "cmgt v0.16b, v15.16b, v1.16b",
|
|
n: &nodeImpl{
|
|
instruction: CMGT,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0xe0, 0x35, 0x21, 0x4e},
|
|
},
|
|
{
|
|
name: "cmhi v0.8h, v15.8h, v1.8h",
|
|
n: &nodeImpl{
|
|
instruction: CMHI,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0xe0, 0x35, 0x61, 0x6e},
|
|
},
|
|
{
|
|
name: "cmhi v0.4h, v15.4h, v1.4h",
|
|
n: &nodeImpl{
|
|
instruction: CMHI,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
vectorArrangement: VectorArrangement4H,
|
|
},
|
|
exp: []byte{0xe0, 0x35, 0x61, 0x2e},
|
|
},
|
|
{
|
|
name: "cmge v0.4s, v15.4s, v1.4s",
|
|
n: &nodeImpl{
|
|
instruction: CMGE,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0xe0, 0x3d, 0xa1, 0x4e},
|
|
},
|
|
{
|
|
name: "cmge v0.2s, v15.2s, v1.2s",
|
|
n: &nodeImpl{
|
|
instruction: CMGE,
|
|
dstReg: RegV0,
|
|
srcReg: RegV1,
|
|
srcReg2: RegV15,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0xe0, 0x3d, 0xa1, 0xe},
|
|
},
|
|
{
|
|
name: "cmhs v30.2d, v4.2d, v11.2d",
|
|
n: &nodeImpl{
|
|
instruction: CMHS,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x9e, 0x3c, 0xeb, 0x6e},
|
|
},
|
|
{
|
|
name: "fcmeq v30.2d, v4.2d, v11.2d",
|
|
n: &nodeImpl{
|
|
instruction: FCMEQ,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x9e, 0xe4, 0x6b, 0x4e},
|
|
},
|
|
{
|
|
name: "fcmeq v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: FCMEQ,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xe4, 0x2b, 0x4e},
|
|
},
|
|
{
|
|
name: "fcmeq v30.2s, v4.2s, v11.2s",
|
|
n: &nodeImpl{
|
|
instruction: FCMEQ,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x9e, 0xe4, 0x2b, 0xe},
|
|
},
|
|
{
|
|
name: "fcmgt v30.2d, v4.2d, v11.2d",
|
|
n: &nodeImpl{
|
|
instruction: FCMGT,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x9e, 0xe4, 0xeb, 0x6e},
|
|
},
|
|
{
|
|
name: "fcmgt v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: FCMGT,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xe4, 0xab, 0x6e},
|
|
},
|
|
{
|
|
name: "fcmgt v30.2s, v4.2s, v11.2s",
|
|
n: &nodeImpl{
|
|
instruction: FCMGT,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x9e, 0xe4, 0xab, 0x2e},
|
|
},
|
|
{
|
|
name: "fcmge v30.2d, v4.2d, v11.2d",
|
|
n: &nodeImpl{
|
|
instruction: FCMGE,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x9e, 0xe4, 0x6b, 0x6e},
|
|
},
|
|
{
|
|
name: "fcmge v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: FCMGE,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xe4, 0x2b, 0x6e},
|
|
},
|
|
{
|
|
name: "fcmge v30.2s, v4.2s, v11.2s",
|
|
n: &nodeImpl{
|
|
instruction: FCMGE,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x9e, 0xe4, 0x2b, 0x2e},
|
|
},
|
|
{
|
|
name: "fdiv v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: VFDIV,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xfc, 0x2b, 0x6e},
|
|
},
|
|
{
|
|
name: "fdiv v30.2s, v4.2s, v11.2s",
|
|
n: &nodeImpl{
|
|
instruction: VFDIV,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x9e, 0xfc, 0x2b, 0x2e},
|
|
},
|
|
{
|
|
name: "fdiv v30.2d, v4.2d, v11.2d",
|
|
n: &nodeImpl{
|
|
instruction: VFDIV,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x9e, 0xfc, 0x6b, 0x6e},
|
|
},
|
|
{
|
|
name: "fmul v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: VFMUL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xdc, 0x2b, 0x6e},
|
|
},
|
|
{
|
|
name: "fmul v30.2s, v4.2s, v11.2s",
|
|
n: &nodeImpl{
|
|
instruction: VFMUL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x9e, 0xdc, 0x2b, 0x2e},
|
|
},
|
|
{
|
|
name: "fmul v30.2d, v4.2d, v11.2d",
|
|
n: &nodeImpl{
|
|
instruction: VFMUL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x9e, 0xdc, 0x6b, 0x6e},
|
|
},
|
|
{
|
|
name: "fmin v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: VFMIN,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xf4, 0xab, 0x4e},
|
|
},
|
|
{
|
|
name: "fmin v30.2s, v4.2s, v11.2s",
|
|
n: &nodeImpl{
|
|
instruction: VFMIN,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x9e, 0xf4, 0xab, 0xe},
|
|
},
|
|
{
|
|
name: "fmin v30.2d, v4.2d, v11.2d",
|
|
n: &nodeImpl{
|
|
instruction: VFMIN,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x9e, 0xf4, 0xeb, 0x4e},
|
|
},
|
|
{
|
|
name: "fmax v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: VFMAX,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xf4, 0x2b, 0x4e},
|
|
},
|
|
{
|
|
name: "fmax v30.2s, v4.2s, v11.2s",
|
|
n: &nodeImpl{
|
|
instruction: VFMAX,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x9e, 0xf4, 0x2b, 0xe},
|
|
},
|
|
{
|
|
name: "fmax v30.2d, v4.2d, v11.2d",
|
|
n: &nodeImpl{
|
|
instruction: VFMAX,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x9e, 0xf4, 0x6b, 0x4e},
|
|
},
|
|
{
|
|
name: "mul v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: VMUL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0x9c, 0xab, 0x4e},
|
|
},
|
|
{
|
|
name: "mul v30.16b, v4.16b, v11.16b",
|
|
n: &nodeImpl{
|
|
instruction: VMUL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x9e, 0x9c, 0x2b, 0x4e},
|
|
},
|
|
{
|
|
name: "sqadd v30.2d, v4.2d, v11.2d",
|
|
n: &nodeImpl{
|
|
instruction: VSQADD,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x9e, 0xc, 0xeb, 0x4e},
|
|
},
|
|
{
|
|
name: "sqadd v30.8h, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: VSQADD,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0xc, 0x6b, 0x4e},
|
|
},
|
|
{
|
|
name: "uqadd v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: VUQADD,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xc, 0xab, 0x6e},
|
|
},
|
|
{
|
|
name: "uqadd v30.8h, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: VUQADD,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0xc, 0x6b, 0x6e},
|
|
},
|
|
{
|
|
name: "smax v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: SMAX,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0x64, 0xab, 0x4e},
|
|
},
|
|
{
|
|
name: "smax v30.8h, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: SMAX,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0x64, 0x6b, 0x4e},
|
|
},
|
|
{
|
|
name: "smin v30.16b, v4.16b, v11.16b",
|
|
n: &nodeImpl{
|
|
instruction: SMIN,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x9e, 0x6c, 0x2b, 0x4e},
|
|
},
|
|
{
|
|
name: "smin v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: SMIN,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0x6c, 0xab, 0x4e},
|
|
},
|
|
{
|
|
name: "umin v30.16b, v4.16b, v11.16b",
|
|
n: &nodeImpl{
|
|
instruction: UMIN,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x9e, 0x6c, 0x2b, 0x6e},
|
|
},
|
|
{
|
|
name: "umin v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: UMIN,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0x6c, 0xab, 0x6e},
|
|
},
|
|
{
|
|
name: "umax v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: UMAX,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0x64, 0xab, 0x6e},
|
|
},
|
|
{
|
|
name: "umax v30.8h, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: UMAX,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0x64, 0x6b, 0x6e},
|
|
},
|
|
{
|
|
name: "umax v30.8h, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: URHADD,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0x14, 0x6b, 0x6e},
|
|
},
|
|
{
|
|
name: "umax v30.16b, v4.16b, v11.16b",
|
|
n: &nodeImpl{
|
|
instruction: URHADD,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x9e, 0x14, 0x2b, 0x6e},
|
|
},
|
|
{
|
|
name: "sqsub v30.16b, v4.16b, v11.16b",
|
|
n: &nodeImpl{
|
|
instruction: VSQSUB,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x9e, 0x2c, 0x2b, 0x4e},
|
|
},
|
|
{
|
|
name: "sqsub v308hb, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: VSQSUB,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0x2c, 0x6b, 0x4e},
|
|
},
|
|
{
|
|
name: "uqsub v30.16b, v4.16b, v11.16b",
|
|
n: &nodeImpl{
|
|
instruction: VUQSUB,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x9e, 0x2c, 0x2b, 0x6e},
|
|
},
|
|
{
|
|
name: "uqsub v308hb, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: VUQSUB,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0x2c, 0x6b, 0x6e},
|
|
},
|
|
{
|
|
name: "umlal v0.2d, v6.2s, v2.2s",
|
|
n: &nodeImpl{
|
|
instruction: VUMLAL,
|
|
dstReg: RegV0,
|
|
srcReg: RegV2,
|
|
srcReg2: RegV6,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0xc0, 0x80, 0xa2, 0x2e},
|
|
},
|
|
{
|
|
name: "umlal v0.4s, v6.4h, v2.4h",
|
|
n: &nodeImpl{
|
|
instruction: VUMLAL,
|
|
dstReg: RegV0,
|
|
srcReg: RegV2,
|
|
srcReg2: RegV6,
|
|
vectorArrangement: VectorArrangement4H,
|
|
},
|
|
exp: []byte{0xc0, 0x80, 0x62, 0x2e},
|
|
},
|
|
{
|
|
name: "umlal v0.8h, v6.8b, v2.8b",
|
|
n: &nodeImpl{
|
|
instruction: VUMLAL,
|
|
dstReg: RegV0,
|
|
srcReg: RegV2,
|
|
srcReg2: RegV6,
|
|
vectorArrangement: VectorArrangement8B,
|
|
},
|
|
exp: []byte{0xc0, 0x80, 0x22, 0x2e},
|
|
},
|
|
{
|
|
name: "bit v30.16b, v4.16b, v11.16b",
|
|
n: &nodeImpl{
|
|
instruction: VBIT,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x9e, 0x1c, 0xab, 0x6e},
|
|
},
|
|
{
|
|
name: "bit v30.8b, v4.8b, v11.8b",
|
|
n: &nodeImpl{
|
|
instruction: VBIT,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8B,
|
|
},
|
|
exp: []byte{0x9e, 0x1c, 0xab, 0x2e},
|
|
},
|
|
{
|
|
name: "sqrdmulh v30.8h, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: SQRDMULH,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0xb4, 0x6b, 0x6e},
|
|
},
|
|
{
|
|
name: "sqrdmulh v30.4s, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: SQRDMULH,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xb4, 0xab, 0x6e},
|
|
},
|
|
{
|
|
name: "smull v30.8h, v4.8b, v11.8b",
|
|
n: &nodeImpl{
|
|
instruction: SMULL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8B,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0x2b, 0xe},
|
|
},
|
|
{
|
|
name: "smull v30.4s, v4.4h, v11.4h",
|
|
n: &nodeImpl{
|
|
instruction: SMULL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4H,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0x6b, 0xe},
|
|
},
|
|
{
|
|
name: "smull v30.2d, v4.2s, v11.2s",
|
|
n: &nodeImpl{
|
|
instruction: SMULL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0xab, 0xe},
|
|
},
|
|
{
|
|
name: "smull2 v30.8h, v4.16b, v11.16b",
|
|
n: &nodeImpl{
|
|
instruction: SMULL2,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0x2b, 0x4e},
|
|
},
|
|
{
|
|
name: "smull2 v30.4s, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: SMULL2,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0x6b, 0x4e},
|
|
},
|
|
{
|
|
name: "smull2 v30.2d, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: SMULL2,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0xab, 0x4e},
|
|
},
|
|
|
|
//////////////////////
|
|
|
|
{
|
|
name: "umull v30.8h, v4.8b, v11.8b",
|
|
n: &nodeImpl{
|
|
instruction: UMULL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8B,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0x2b, 0x2e},
|
|
},
|
|
{
|
|
name: "umull v30.4s, v4.4h, v11.4h",
|
|
n: &nodeImpl{
|
|
instruction: UMULL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4H,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0x6b, 0x2e},
|
|
},
|
|
{
|
|
name: "umull v30.2d, v4.2s, v11.2s",
|
|
n: &nodeImpl{
|
|
instruction: UMULL,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement2S,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0xab, 0x2e},
|
|
},
|
|
{
|
|
name: "umull2 v30.8h, v4.16b, v11.16b",
|
|
n: &nodeImpl{
|
|
instruction: UMULL2,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0x2b, 0x6e},
|
|
},
|
|
{
|
|
name: "umull2 v30.4s, v4.8h, v11.8h",
|
|
n: &nodeImpl{
|
|
instruction: UMULL2,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0x6b, 0x6e},
|
|
},
|
|
{
|
|
name: "umull2 v30.2d, v4.4s, v11.4s",
|
|
n: &nodeImpl{
|
|
instruction: UMULL2,
|
|
dstReg: RegV30,
|
|
srcReg: RegV11,
|
|
srcReg2: RegV4,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0x9e, 0xc0, 0xab, 0x6e},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeTwoVectorRegistersToVectorRegister(buf, tc.n)
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_EncodeRegisterToVectorRegister(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
n *nodeImpl
|
|
exp []byte
|
|
}{
|
|
{
|
|
name: "ins v10.d[0], x10",
|
|
n: &nodeImpl{
|
|
instruction: INSGEN,
|
|
dstReg: RegV10,
|
|
srcReg: RegR10,
|
|
vectorArrangement: VectorArrangementD,
|
|
},
|
|
exp: []byte{0x4a, 0x1d, 0x8, 0x4e},
|
|
},
|
|
{
|
|
name: "ins v10.d[1], x10",
|
|
n: &nodeImpl{
|
|
instruction: INSGEN,
|
|
dstReg: RegV10,
|
|
srcReg: RegR10,
|
|
vectorArrangement: VectorArrangementD,
|
|
dstVectorIndex: 1,
|
|
},
|
|
exp: []byte{0x4a, 0x1d, 0x18, 0x4e},
|
|
},
|
|
{
|
|
name: "dup v10.2d, x10",
|
|
n: &nodeImpl{
|
|
instruction: DUPGEN,
|
|
srcReg: RegR10,
|
|
dstReg: RegV10,
|
|
vectorArrangement: VectorArrangement2D,
|
|
},
|
|
exp: []byte{0x4a, 0xd, 0x8, 0x4e},
|
|
},
|
|
{
|
|
name: "dup v1.4s, w30",
|
|
n: &nodeImpl{
|
|
instruction: DUPGEN,
|
|
srcReg: RegR30,
|
|
dstReg: RegV1,
|
|
vectorArrangement: VectorArrangement4S,
|
|
},
|
|
exp: []byte{0xc1, 0xf, 0x4, 0x4e},
|
|
},
|
|
{
|
|
name: "dup v30.8h, w1",
|
|
n: &nodeImpl{
|
|
instruction: DUPGEN,
|
|
srcReg: RegR1,
|
|
dstReg: RegV30,
|
|
vectorArrangement: VectorArrangement8H,
|
|
},
|
|
exp: []byte{0x3e, 0xc, 0x2, 0x4e},
|
|
},
|
|
{
|
|
name: "dup v30.16b, w1",
|
|
n: &nodeImpl{
|
|
instruction: DUPGEN,
|
|
srcReg: RegR1,
|
|
dstReg: RegV30,
|
|
vectorArrangement: VectorArrangement16B,
|
|
},
|
|
exp: []byte{0x3e, 0xc, 0x1, 0x4e},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeRegisterToVectorRegister(buf, tc.n)
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_maybeFlushConstPool(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
c []byte
|
|
exp []byte
|
|
}{
|
|
{
|
|
name: "1 byte consts",
|
|
c: []byte{1},
|
|
exp: []byte{
|
|
// 0x0:
|
|
// b #0x8
|
|
0x2, 0x0, 0x0, 0x14,
|
|
// 0x4:
|
|
0x1,
|
|
0x0, 0x0, 0x0, // padding to be 4-byte aligned.
|
|
// 0x8: <- branch dst.
|
|
},
|
|
},
|
|
{
|
|
name: "2 byte consts",
|
|
c: []byte{0xff, 0xfe},
|
|
exp: []byte{
|
|
// 0x0:
|
|
// b #0x8
|
|
0x2, 0x0, 0x0, 0x14,
|
|
// 0x4:
|
|
0xff, 0xfe,
|
|
0x0, 0x0, // padding to be 4-byte aligned.
|
|
// 0x8: <- branch dst.
|
|
},
|
|
},
|
|
{
|
|
name: "3 byte consts",
|
|
c: []byte{0xff, 0xfe, 0xa},
|
|
exp: []byte{
|
|
// 0x0:
|
|
// b #0x8
|
|
0x2, 0x0, 0x0, 0x14,
|
|
// 0x4:
|
|
0xff, 0xfe, 0xa,
|
|
0x0, // padding to be 4-byte aligned.
|
|
// 0x8: <- branch dst.
|
|
},
|
|
},
|
|
{
|
|
name: "4 byte consts",
|
|
c: []byte{1, 2, 3, 4},
|
|
exp: []byte{
|
|
// 0x0:
|
|
// b #0x8
|
|
0x2, 0x0, 0x0, 0x14,
|
|
// 0x4:
|
|
0x1, 0x2, 0x3, 0x4,
|
|
// 0x8: <- branch dst.
|
|
},
|
|
},
|
|
{
|
|
name: "12 byte consts",
|
|
c: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
|
|
exp: []byte{
|
|
// 0x0:
|
|
// b #0x10
|
|
0x4, 0x0, 0x0, 0x14,
|
|
// 0x4:
|
|
1, 2, 3, 4,
|
|
5, 6, 7, 8,
|
|
9, 10, 11, 12,
|
|
// 0x10: <- branch dst.
|
|
},
|
|
},
|
|
{
|
|
name: "16 byte consts",
|
|
c: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
|
|
exp: []byte{
|
|
// 0x0:
|
|
// b #0x14
|
|
0x5, 0x0, 0x0, 0x14,
|
|
// 0x04:
|
|
0x1, 0x2, 0x3, 0x4,
|
|
0x5, 0x6, 0x7, 0x8,
|
|
0x9, 0xa, 0xb, 0xc,
|
|
0xd, 0xe, 0xf, 0x10,
|
|
// 0x14: <- branch dst.
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
sc := asm.NewStaticConst(tc.c)
|
|
a.pool.AddConst(sc, 0)
|
|
|
|
var called bool
|
|
sc.AddOffsetFinalizedCallback(func(uint64) {
|
|
called = true
|
|
})
|
|
|
|
a.MaxDisplacementForConstantPool = 0
|
|
buf := code.NextCodeSection()
|
|
a.maybeFlushConstPool(buf, false)
|
|
require.True(t, called)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_EncodeStaticConstToVectorRegister(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
n *nodeImpl
|
|
exp []byte
|
|
}{
|
|
{
|
|
name: "ldr q8, #8",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
dstReg: RegV8,
|
|
vectorArrangement: VectorArrangementQ,
|
|
staticConst: asm.NewStaticConst([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}),
|
|
},
|
|
exp: []byte{
|
|
// 0x0: ldr q8, #8
|
|
0x48, 0x0, 0x0, 0x9c,
|
|
// Emitted after the end of function.
|
|
// 0x4: br #4 (See AssemblerImpl.maybeFlushConstPool)
|
|
0x0, 0x0, 0x0, 0x14,
|
|
// 0x8: consts.
|
|
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
|
|
0x10,
|
|
},
|
|
},
|
|
{
|
|
name: "ldr d30, #8",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
dstReg: RegV30,
|
|
vectorArrangement: VectorArrangementD,
|
|
staticConst: asm.NewStaticConst([]byte{1, 2, 3, 4, 5, 6, 7, 8}),
|
|
},
|
|
exp: []byte{
|
|
// 0x0: ldr d30, #8
|
|
0x5e, 0x0, 0x0, 0x5c,
|
|
// Emitted after the end of function.
|
|
// 0x4: br #4 (See AssemblerImpl.maybeFlushConstPool)
|
|
0x0, 0x0, 0x0, 0x14,
|
|
// 0x8: consts.
|
|
0x1, 0x2, 0x3, 0x4,
|
|
0x5, 0x6, 0x7, 0x8,
|
|
},
|
|
},
|
|
{
|
|
name: "ldr s8, #8",
|
|
n: &nodeImpl{
|
|
instruction: VMOV,
|
|
dstReg: RegV8,
|
|
vectorArrangement: VectorArrangementS,
|
|
staticConst: asm.NewStaticConst([]byte{1, 2, 3, 4}),
|
|
},
|
|
exp: []byte{
|
|
// 0x0: ldr s8, #8
|
|
0x48, 0x0, 0x0, 0x1c,
|
|
// Emitted after the end of function.
|
|
// 0x4: br #4 (See AssemblerImpl.maybeFlushConstPool)
|
|
0x0, 0x0, 0x0, 0x14,
|
|
// 0x8: consts.
|
|
0x1, 0x2, 0x3, 0x4,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
buf := code.NextCodeSection()
|
|
err := a.encodeStaticConstToVectorRegister(buf, tc.n)
|
|
require.NoError(t, err)
|
|
a.maybeFlushConstPool(buf, true)
|
|
|
|
err = a.Assemble(buf)
|
|
require.NoError(t, err)
|
|
|
|
actual := buf.Bytes()
|
|
require.Equal(t, tc.exp, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssemblerImpl_encodeADR_staticConst(t *testing.T) {
|
|
const beforeADRByteNum uint64 = 2
|
|
|
|
tests := []struct {
|
|
name string
|
|
expADRInstructionBytes []byte
|
|
offsetOfConstInBinary uint64
|
|
reg asm.Register
|
|
}{
|
|
{
|
|
// #8 = offsetOfConstInBinary - beforeADRByteNum.
|
|
name: "adr x12, #8",
|
|
reg: RegR12,
|
|
offsetOfConstInBinary: 10,
|
|
expADRInstructionBytes: []byte{0x4c, 0x0, 0x0, 0x10},
|
|
},
|
|
{
|
|
// #0x7fffd = offsetOfConstInBinary - beforeADRByteNum.
|
|
name: "adr x12, #0x7fffd",
|
|
reg: RegR12,
|
|
offsetOfConstInBinary: 0x7ffff,
|
|
expADRInstructionBytes: []byte{0xec, 0xff, 0x3f, 0x30},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
code := asm.CodeSegment{}
|
|
defer func() { require.NoError(t, code.Unmap()) }()
|
|
|
|
sc := asm.NewStaticConst([]byte{1, 2, 3, 4}) // Arbitrary data is fine.
|
|
|
|
a := NewAssembler(asm.NilRegister)
|
|
|
|
buf := code.NextCodeSection()
|
|
buf.AppendBytes(make([]byte, beforeADRByteNum))
|
|
|
|
err := a.encodeADR(buf, &nodeImpl{instruction: ADR, dstReg: tc.reg, staticConst: sc})
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(a.pool.Consts))
|
|
require.Equal(t, sc, a.pool.Consts[0])
|
|
require.Equal(t, beforeADRByteNum, a.pool.FirstUseOffsetInBinary)
|
|
|
|
// Finalize the ADR instruction bytes.
|
|
sc.SetOffsetInBinary(tc.offsetOfConstInBinary)
|
|
|
|
actual := buf.Bytes()[beforeADRByteNum : beforeADRByteNum+4]
|
|
require.Equal(t, tc.expADRInstructionBytes, actual, hex.EncodeToString(actual))
|
|
})
|
|
}
|
|
}
|