From 2b2a72d54ebdcf1f3045dec929e5f6a223fb78f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Balv=C3=ADn?= Date: Wed, 7 Oct 2026 02:12:04 +0200 Subject: [PATCH] fix(asm): encode the arm64 bitfield aliases with their own opc Assisted-by: GLM 5.3 Flash --- asm/arm64_assemble.go | 5 ++++- asm/arm64_encode_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/asm/arm64_assemble.go b/asm/arm64_assemble.go index 5b88eba..dc6855b 100644 --- a/asm/arm64_assemble.go +++ b/asm/arm64_assemble.go @@ -3636,7 +3636,10 @@ func encodeARM64BitfieldAlias(mnem string, baseOp uint32, ops []*ast.Operand) ([ case "BFXIL", "BFXILW": immr, imms = lsb, lsb+width-1 default: // BFI, SBFIZ, UBFIZ - immr, imms = (-lsb)%bits, width-1 + // immr = (bits - lsb) mod bits, the toolchain's 64-r form with the + // zero lsb folding to zero (Go's % keeps the sign, so the operand + // order matters here). + immr, imms = (bits-lsb)%bits, width-1 } return a64wordLE(baseOp | uint32(immr)<<16 | uint32(imms)<<10 | uint32(rn)<<5 | uint32(rd)), nil } diff --git a/asm/arm64_encode_test.go b/asm/arm64_encode_test.go index ef7c3af..c55635e 100644 --- a/asm/arm64_encode_test.go +++ b/asm/arm64_encode_test.go @@ -2186,3 +2186,39 @@ func TestArm64ZRNameNotNumber(t *testing.T) { } } +// TestArm64BitfieldAlias pins the bitfield alias encodings against +// `go tool asm` words: BFI rides the BFM opc at every lsb (asm7.go case 43 +// routes ABFI to ABFM), SBFIZ keeps SBFM and UBFIZ keeps UBFM at the spelled +// width. +func TestArm64BitfieldAlias(t *testing.T) { + got := arm64Words(t, + "\tBFI $0, R1, $1, R2\n"+ + "\tBFIW $0, R1, $1, R2\n"+ + "\tBFI $4, R1, $4, R2\n"+ + "\tSBFIZ $0, R1, $1, R2\n"+ + "\tSBFIZW $0, R1, $1, R2\n"+ + "\tUBFIZ $0, R1, $1, R2\n"+ + "\tUBFIZW $0, R1, $1, R2\n"+ + "\tUBFIZ $4, R1, $4, R2\n"+ + "\tBFXIL $0, R1, $8, R2\n") + want := []uint32{ + 0xb3400022, // BFM X2, X1, #0, #0 (BFI lsb 0) + 0x33000022, // BFM W2, W1, #0, #0 (BFIW lsb 0) + 0xb37c0c22, // BFM X2, X1, #28, #3 (BFI lsb 4) + 0x93400022, // SBFM X2, X1, #0, #0 (SBFIZ lsb 0) + 0x13000022, // SBFM W2, W1, #0, #0 (SBFIZW lsb 0) + 0xd3400022, // UBFM X2, X1, #0, #0 (UBFIZ lsb 0) + 0x53000022, // UBFM W2, W1, #0, #0 (UBFIZW lsb 0) + 0xd37c0c22, // UBFM X2, X1, #28, #3 (UBFIZ lsb 4) + 0xb3401c22, // BFM X2, X1, #0, #7 (BFXIL lsb 0) + 0xd65f03c0, // RET + } + if len(got) != len(want) { + t.Fatalf("word count = %d, want %d", len(got), len(want)) + } + for i := range want { + if got[i] != want[i] { + t.Errorf("word %d = %08x, want %08x", i, got[i], want[i]) + } + } +}