blob: 7e2bfc55bdffea4ad36e9a7da2a9dc5f0d6d425e [file] [edit]
// 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)
}
})
}