#![cfg(feature = "std")]
use fARM64::decode::decode;
use fARM64::{encode, FeatureSet};
fn assert_roundtrip(word: u32) {
let insn = decode(word, 0, FeatureSet::ALL);
assert!(!insn.is_invalid(), "{:08X} decoded Invalid", word);
let enc = encode(&insn).unwrap_or_else(|e| {
panic!(
"{:08X} ({}) encode error {:?}",
word,
insn.mnemonic().name(),
e
)
});
assert_eq!(
enc,
word,
"{:08X} ({}) re-encoded to {:08X}",
word,
insn.mnemonic().name(),
enc
);
let insn2 = decode(enc, 0, FeatureSet::ALL);
assert_eq!(
insn.mnemonic(),
insn2.mnemonic(),
"{:08X} mnemonic drift",
word
);
assert_eq!(
insn.op_count(),
insn2.op_count(),
"{:08X} operand-count drift",
word
);
}
fn is_invalid(word: u32) -> bool {
decode(word, 0, FeatureSet::ALL).is_invalid()
}
fn mnem(word: u32) -> &'static str {
decode(word, 0, FeatureSet::ALL).mnemonic().name()
}
#[test]
fn ins_general_q0_reserved() {
for &(bad, good) in &[
(0x0E051C11u32, 0x4E051C11u32), (0x0E031C11, 0x4E031C11), (0x0E0B1C11, 0x4E0B1C11), ] {
assert!(
is_invalid(bad),
"{:08X} INS-general Q==0 should be Invalid",
bad
);
assert!(
!is_invalid(good),
"{:08X} canonical INS-general should decode",
good
);
assert_eq!(mnem(good), "mov");
assert_roundtrip(good);
}
}
#[test]
fn ins_element_q0_reserved() {
for &(bad, good) in &[
(0x2E010411u32, 0x6E010411u32), (0x2E080411, 0x6E080411), (0x2E020411, 0x6E020411), ] {
assert!(
is_invalid(bad),
"{:08X} INS-element Q==0 should be Invalid",
bad
);
assert!(
!is_invalid(good),
"{:08X} canonical INS-element should decode",
good
);
assert_eq!(mnem(good), "mov");
assert_roundtrip(good);
}
}
#[test]
fn copy_other_forms_unaffected() {
for &w in &[
0x0E010411u32, 0x4E080C11, 0x0E010411, 0x0E033C11, 0x4E0C2C11, ] {
assert!(
!is_invalid(w),
"{:08X} non-INS copy form should still decode",
w
);
assert_roundtrip(w);
}
}
#[test]
#[cfg(feature = "sve")]
fn saddlbt_slot01_reserved() {
for bad in [0x455386ABu32, 0x459386AB, 0x45D386AB] {
assert!(
is_invalid(bad),
"{:08X} SADDLBT <10>=1 should be Invalid",
bad
);
}
let cases: &[(u32, &str)] = &[
(0x455382AB, "saddlbt"), (0x459382AB, "saddlbt"), (0x45D382AB, "saddlbt"), (0x45538AAB, "ssublbt"),
(0x45538EAB, "ssubltb"),
];
for &(w, m) in cases {
assert_eq!(mnem(w), m, "{:08X} mnemonic", w);
assert_roundtrip(w);
}
}
#[test]
#[cfg(feature = "sve")]
fn pmull_s_size10_reserved() {
for bad in [0x45896FE8u32, 0x458669C7, 0x45826820, 0x45826C20] {
assert!(is_invalid(bad), "{:08X} PMULL .s should be Invalid", bad);
}
for &(w, m) in &[
(0x45426820u32, "pmullb"), (0x45426C20, "pmullt"), (0x45C26820, "pmullb"), (0x45026820, "pmullb"), ] {
assert_eq!(mnem(w), m, "{:08X} mnemonic", w);
assert_roundtrip(w);
}
assert!(
!is_invalid(0x45827020),
"45827020 smullb .s should still decode"
);
assert_eq!(mnem(0x45827020), "smullb");
assert_roundtrip(0x45827020);
}
#[test]
#[cfg(feature = "sve")]
fn fp_imm_bits9_6_reserved() {
for &(bad, good) in &[
(0x655A9DE5u32, 0x655A9C25u32), (0x65DE8707, 0x65DE8407), (0x65DF91FF, 0x65DF903F), (0x65DB80E6, 0x65DB8026), ] {
assert!(
is_invalid(bad),
"{:08X} FP-imm <9:6>!=0 should be Invalid",
bad
);
assert!(
!is_invalid(good),
"{:08X} canonical FP-imm should decode",
good
);
assert_roundtrip(good);
}
assert_eq!(mnem(0x655A9C25), "fmul");
assert_eq!(mnem(0x65DE8407), "fmax");
assert_eq!(mnem(0x65DF903F), "fmin");
assert_eq!(mnem(0x65DB8026), "fsubr");
}