fix(test): add arm64 encoding tests for Go 1.26 coverage compatibility
Assisted-by: MiMo V2.5 Pro
This commit is contained in:
@@ -214,7 +214,13 @@ func encodeARM64Instr(instr *ast.Instr, pc int, offsets map[string]int, fi arm64
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register-register data processing.
|
// Register-register data processing.
|
||||||
|
// ASR/LSL/LSR/ROR with immediate operands use bitfield encoding (SBFM/UBFM).
|
||||||
if enc, ok := a64InstrTable[mnem]; ok && enc.format == a64FDPSR {
|
if enc, ok := a64InstrTable[mnem]; ok && enc.format == a64FDPSR {
|
||||||
|
isShift := mnem == "ASR" || mnem == "ASRW" || mnem == "LSL" || mnem == "LSLW" ||
|
||||||
|
mnem == "LSR" || mnem == "LSRW" || mnem == "ROR" || mnem == "RORW"
|
||||||
|
if isShift && len(ops) >= 2 && isImmOperand(ops[0]) {
|
||||||
|
return encodeARM64Bitfield(mnem, enc.op, ops)
|
||||||
|
}
|
||||||
return encodeARM64DPSR(mnem, enc.op, ops)
|
return encodeARM64DPSR(mnem, enc.op, ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -365,6 +365,199 @@ func TestArm64ResolvePseudo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestArm64FPSel tests FP conditional select encoding.
|
||||||
|
func TestArm64FPSel(t *testing.T) {
|
||||||
|
src := `#include "textflag.h"
|
||||||
|
TEXT ·f(SB), NOSPLIT, $0-0
|
||||||
|
FCSELD GE, F10, F11, F12
|
||||||
|
RET
|
||||||
|
`
|
||||||
|
f, errs := parser.Parse("test_arm64.s", src)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("parse: %v", errs)
|
||||||
|
}
|
||||||
|
img, err := AssembleFileARM64(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("AssembleFileARM64: %v", err)
|
||||||
|
}
|
||||||
|
// FCSELD should be 4 bytes + RET 4 bytes = 8
|
||||||
|
if img.Funcs[0].Size != 8 {
|
||||||
|
t.Errorf("size: got %d, want 8", img.Funcs[0].Size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestArm64FPCvt tests FP conversion encoding.
|
||||||
|
func TestArm64FPCvt(t *testing.T) {
|
||||||
|
src := `#include "textflag.h"
|
||||||
|
TEXT ·f(SB), NOSPLIT, $0-0
|
||||||
|
FCVTZSD F4, R0
|
||||||
|
SCVTFD R4, F8
|
||||||
|
RET
|
||||||
|
`
|
||||||
|
f, errs := parser.Parse("test_arm64.s", src)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("parse: %v", errs)
|
||||||
|
}
|
||||||
|
img, err := AssembleFileARM64(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("AssembleFileARM64: %v", err)
|
||||||
|
}
|
||||||
|
if img.Funcs[0].Size != 12 {
|
||||||
|
t.Errorf("size: got %d, want 12", img.Funcs[0].Size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestArm64CSEL tests conditional select encoding.
|
||||||
|
func TestArm64CSEL(t *testing.T) {
|
||||||
|
src := `#include "textflag.h"
|
||||||
|
TEXT ·f(SB), NOSPLIT, $0-0
|
||||||
|
CSEL EQ, R0, R1, R2
|
||||||
|
CSET NE, R3
|
||||||
|
CINC GE, R4, R5
|
||||||
|
RET
|
||||||
|
`
|
||||||
|
f, errs := parser.Parse("test_arm64.s", src)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("parse: %v", errs)
|
||||||
|
}
|
||||||
|
img, err := AssembleFileARM64(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("AssembleFileARM64: %v", err)
|
||||||
|
}
|
||||||
|
if img.Funcs[0].Size != 16 {
|
||||||
|
t.Errorf("size: got %d, want 16", img.Funcs[0].Size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestArm64CRC32 tests CRC32 encoding.
|
||||||
|
func TestArm64CRC32(t *testing.T) {
|
||||||
|
src := `#include "textflag.h"
|
||||||
|
TEXT ·f(SB), NOSPLIT, $0-0
|
||||||
|
CRC32B R0, R2
|
||||||
|
CRC32W R6, R8
|
||||||
|
RET
|
||||||
|
`
|
||||||
|
f, errs := parser.Parse("test_arm64.s", src)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("parse: %v", errs)
|
||||||
|
}
|
||||||
|
img, err := AssembleFileARM64(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("AssembleFileARM64: %v", err)
|
||||||
|
}
|
||||||
|
if img.Funcs[0].Size != 12 {
|
||||||
|
t.Errorf("size: got %d, want 12", img.Funcs[0].Size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestArm64Bitfield tests bitfield/shift encoding.
|
||||||
|
func TestArm64Bitfield(t *testing.T) {
|
||||||
|
src := `#include "textflag.h"
|
||||||
|
TEXT ·f(SB), NOSPLIT, $0-0
|
||||||
|
ASR $4, R0, R1
|
||||||
|
LSL $12, R4, R5
|
||||||
|
EXTR $8, R0, R1, R2
|
||||||
|
RET
|
||||||
|
`
|
||||||
|
f, errs := parser.Parse("test_arm64.s", src)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("parse: %v", errs)
|
||||||
|
}
|
||||||
|
img, err := AssembleFileARM64(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("AssembleFileARM64: %v", err)
|
||||||
|
}
|
||||||
|
if img.Funcs[0].Size != 16 {
|
||||||
|
t.Errorf("size: got %d, want 16", img.Funcs[0].Size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestArm64SIMD tests SIMD encoding (via the instruction table).
|
||||||
|
func TestArm64SIMD(t *testing.T) {
|
||||||
|
// Verify SIMD instructions are in the table.
|
||||||
|
for _, mnem := range []string{"VADD", "VSUB", "VMUL"} {
|
||||||
|
if _, ok := a64InstrTable[mnem]; !ok {
|
||||||
|
t.Errorf("%s not in instruction table", mnem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestArm64LoadImm64 tests 64-bit immediate loading.
|
||||||
|
func TestArm64LoadImm64(t *testing.T) {
|
||||||
|
src := `#include "textflag.h"
|
||||||
|
TEXT ·f(SB), NOSPLIT, $0-0
|
||||||
|
MOVD $0x123456789ABCDEF0, R0
|
||||||
|
MOVD $0, R1
|
||||||
|
MOVD $1, R2
|
||||||
|
RET
|
||||||
|
`
|
||||||
|
f, errs := parser.Parse("test_arm64.s", src)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("parse: %v", errs)
|
||||||
|
}
|
||||||
|
img, err := AssembleFileARM64(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("AssembleFileARM64: %v", err)
|
||||||
|
}
|
||||||
|
// $0x123456789ABCDEF0 needs 4 MOVZ/MOVK instructions (16 bytes)
|
||||||
|
// $0 is 1 instruction (4 bytes)
|
||||||
|
// $1 is 1 bitmask instruction (4 bytes)
|
||||||
|
// RET is 1 instruction (4 bytes)
|
||||||
|
if img.Funcs[0].Size != 28 {
|
||||||
|
t.Errorf("size: got %d, want 28", img.Funcs[0].Size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestArm64BranchCond tests conditional branch encoding.
|
||||||
|
func TestArm64BranchCond(t *testing.T) {
|
||||||
|
src := `#include "textflag.h"
|
||||||
|
TEXT ·f(SB), NOSPLIT, $0-0
|
||||||
|
BEQ done
|
||||||
|
BNE done
|
||||||
|
BGE done
|
||||||
|
BLT done
|
||||||
|
ADD R4, R5
|
||||||
|
done:
|
||||||
|
RET
|
||||||
|
`
|
||||||
|
f, errs := parser.Parse("test_arm64.s", src)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("parse: %v", errs)
|
||||||
|
}
|
||||||
|
img, err := AssembleFileARM64(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("AssembleFileARM64: %v", err)
|
||||||
|
}
|
||||||
|
// 4 branches + 1 ADD + 1 RET = 24 bytes
|
||||||
|
if img.Funcs[0].Size != 24 {
|
||||||
|
t.Errorf("size: got %d, want 24", img.Funcs[0].Size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestArm64Errors tests error paths.
|
||||||
|
func TestArm64Errors(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
src string
|
||||||
|
}{
|
||||||
|
{"bad mnemonic", "TEXT ·f(SB), NOSPLIT, $0-0\n\tINVALID\tR4\n\tRET\n"},
|
||||||
|
{"bad label", "TEXT ·f(SB), NOSPLIT, $0-0\n\tB\tnosuch\n\tRET\n"},
|
||||||
|
{"bad register", "TEXT ·f(SB), NOSPLIT, $0-0\n\tADD\tR99, R0\n\tRET\n"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
f, errs := parser.Parse("test_arm64.s", tt.src)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := AssembleFileARM64(f)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error, got nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// leWord reads a little-endian uint32 from b.
|
// leWord reads a little-endian uint32 from b.
|
||||||
func leWord(b []byte) uint32 {
|
func leWord(b []byte) uint32 {
|
||||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||||
|
|||||||
Reference in New Issue
Block a user