fn log2(x: u32) -> u32 {
let (mut x, mut log) = (x, 0);
while x != 0 {
x >>= 1;
log += 1;
}
log - 1
}
fn mask(width: u32) -> u64 {
(2_u128.pow(width) - 1) as u64
}
fn bitmask_ror(x: u64, r: u32, width: u32) -> u64 {
let (r, width) = (r as u64, width as u64);
if r == 0 {
return x;
}
let r = r % width;
let a = (x >> r) & mask((width - r) as u32);
let b = x & mask(r as u32);
return (b << (width - r)) | a;
}
fn replicate(pattern: u64, esize: u32, width: u32) -> u64 {
let mut res = 0u64;
for i in (0..width).step_by(esize as usize) {
res |= pattern << i;
}
res
}
pub fn is_modified_immediate(n: u64) -> bool {
(0..16).any(|i| ((n << 33 ^ n << 32 ^ (n * 2) ^ n) << (i * 2)) >> 41 < 1)
}
pub fn bitmask_decode<const M: u32>(n: u8, imms: u8, immr: u8) -> (u64, u64) {
let (n, imms, immr) = (n as u32, imms as u32, immr as u32);
let val = (n << 6) | (!imms & 0b111111);
if (val >> 1) == 0 {
todo!();
}
let len = log2(val);
let levels = 2_u32.pow(len + 1) - 1;
let s = imms & levels;
let r = immr & levels;
let diff = (s.wrapping_sub(r)) & 0b111111;
let esize = 1 << len;
let d = diff & mask(len) as u32;
let welem = mask(s + 1) & mask(esize);
let telem = mask(d + 1) & mask(esize);
let tmask = replicate(telem, esize, M);
let wmask = replicate(bitmask_ror(welem, r, esize), esize, M);
(wmask, tmask)
}
pub fn move_wide_preferred(sf: u32, n: u32, imms: u32, immr: u32) -> bool {
let mut imm = if sf == 0 {
bitmask_decode::<32>(n as u8, imms as u8, immr as u8).0
} else {
bitmask_decode::<64>(n as u8, imms as u8, immr as u8).0
};
if imm & 0xffff_ffff_ffff_0000 == 0
|| imm & 0xffff_ffff_0000_ffff == 0
|| imm & 0xffff_0000_ffff_ffff == 0
|| imm & 0x0000_ffff_ffff_ffff == 0
{
return true;
}
imm = !imm;
if sf == 0 {
imm &= 0xffff_ffff;
}
if imm & 0xffff_ffff_ffff_0000 == 0
|| imm & 0xffff_ffff_0000_ffff == 0
|| imm & 0xffff_0000_ffff_ffff == 0
|| imm & 0x0000_ffff_ffff_ffff == 0
{
return true;
}
return false;
}
pub fn bfx_preferred(sf: u32, uns: u32, imms: u32, immr: u32) -> bool {
if imms < immr {
return false;
}
if imms == (sf << 5) | 0b11111 {
return false;
}
if immr == 0 {
if sf == 0 && (imms == 0b000111 || imms == 0b001111) {
return false;
}
if (sf << 1) | uns == 0b10 && (imms == 0b000111 || imms == 0b001111 || imms == 0b011111) {
return false;
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bitmask() {
assert_eq!(
bitmask_decode::<64>(0, 0b111100, 0b000000).0,
0x5555555555555555
);
assert_eq!(
bitmask_decode::<64>(0, 0b111100, 0b000001).0,
0xaaaaaaaaaaaaaaaa
);
assert_eq!(
bitmask_decode::<64>(0, 0b111000, 0b000000).0,
0x1111111111111111
);
assert_eq!(
bitmask_decode::<64>(0, 0b111001, 0b000011).0,
0x6666666666666666
);
assert_eq!(
bitmask_decode::<64>(0, 0b110000, 0b000000).0,
0x0101010101010101
);
assert_eq!(
bitmask_decode::<64>(0, 0b110000, 0b000000).0,
0x0101010101010101
);
}
}