// Copyright 2026 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package arm64 import ( "math/bits" "testing" "cmd/internal/obj" ) // decodeLogicalImmArrEncoding is translated from DecodeBitMasks in ARM64 // ASL. It implements the decoding logic of imm13 defined by ARM64 specification. func decodeLogicalImmArrEncoding(imm13 uint32, arr uint32) (uint64, bool) { n := (imm13 >> 12) & 1 immr := (imm13 >> 6) & 0x3F imms := imm13 & 0x3F notImms := (^imms) & 0x3F combined := (n << 6) | notImms // if immN::NOT(imms) == '000000x' then Undefined(); end; if combined <= 1 { return 0, false } lenVal := bits.Len32(uint32(combined)) - 1 esize := uint64(1 << lenVal) levels := uint32((1 << lenVal) - 1) // if immediate && (imms AND levels) == levels then Undefined(); end; if (imms & levels) == levels { return 0, false } s := uint64(imms & levels) r := uint64(immr & levels) // welem has s + 1 ones welem := (uint64(1) << (s + 1)) - 1 // Rotate right welem by r bits within esize bits window rotated := welem mask := (uint64(1) << esize) - 1 if r > 0 { r %= esize rotated = ((welem >> r) | (welem << (esize - r))) & mask } // Replicate rotated to fill 64 bits (as encode replicates to 64 bits) wmask := uint64(0) for i := uint64(0); i < 64; i += esize { wmask |= rotated << i } // Now mask back to the arrangement's lane size M var M uint64 switch arr { case ARNG_B: M = 8 case ARNG_H: M = 16 case ARNG_S: M = 32 case ARNG_D: M = 64 default: return 0, false } mask = (uint64(1) << M) - 1 return wmask & mask, true } func FuzzLogicalImmArrEncoding(f *testing.F) { f.Add(uint64(0x55), uint32(ARNG_B)) f.Add(uint64(0xAA), uint32(ARNG_B)) f.Add(uint64(0x0F), uint32(ARNG_B)) f.Add(uint64(0x0101), uint32(ARNG_H)) f.Add(uint64(0x00FF), uint32(ARNG_H)) f.Add(uint64(0x0000FFFF), uint32(ARNG_S)) f.Add(uint64(0x55555555), uint32(ARNG_S)) f.Add(uint64(0x0000FFFF), uint32(ARNG_D)) f.Add(uint64(0x0101010101010101), uint32(ARNG_D)) f.Fuzz(func(t *testing.T, v uint64, arr uint32) { if arr != ARNG_B && arr != ARNG_H && arr != ARNG_S && arr != ARNG_D { return } adjacentAddr := &obj.Addr{ Type: obj.TYPE_REG, Reg: int16(REG_ZARNG) + 0 + (int16(arr) << 5), } encoded, ok := encodeLogicalImmArrEncoding(v, adjacentAddr) if !ok { return } imm13 := encoded >> 5 decoded, ok := decodeLogicalImmArrEncoding(imm13, arr) if !ok { t.Errorf("Failed to decode imm13=0x%x arr=%d", imm13, arr) return } var mask uint64 switch arr { case ARNG_B: mask = 0xFF case ARNG_H: mask = 0xFFFF case ARNG_S: mask = 0xFFFFFFFF case ARNG_D: mask = 0xFFFFFFFFFFFFFFFF } expected := v & mask if decoded != expected { t.Errorf("Fuzz roundtrip failed for v=0x%x arr=%d. Expected 0x%x, got 0x%x (imm13=0x%x)", v, arr, expected, decoded, imm13) } }) }