#![cfg(feature = "std")]
use fARM64::decode::decode;
use fARM64::{encode, Feature, 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 rcw_pair_size_reserved() {
for &(bad, good) in &[
(0x99B1B02Du32, 0x19B1B02Du32), (0x9931A02D, 0x1931A02D), (0x9931902D, 0x1931902D), (0x9931802D, 0x1931802D), (0x9931102D, 0x1931102D), (0x9931302D, 0x1931302D), ] {
assert!(
is_invalid(bad),
"{:08X} RCW-pair size==10 should be Invalid",
bad
);
assert!(
!is_invalid(good),
"{:08X} canonical RCW-pair should decode",
good
);
assert_roundtrip(good);
}
}
#[test]
fn rcw_pair_rcws_size01_preserved() {
for &w in &[
0x59B1B02Du32, 0x5931A02D, 0x19B1B02D, ] {
assert!(!is_invalid(w), "{:08X} RCWS*/RCW* should decode", w);
assert_roundtrip(w);
}
}
#[test]
fn sve_dup_imm_reserved() {
for &(bad, good) in &[
(0x25BCD880u32, 0x25B8D880u32), (0x25BAD880, 0x25B8D880), (0x25BED880, 0x25B8D880), ] {
assert!(
is_invalid(bad),
"{:08X} DUP-imm <18:17>!=00 should be Invalid",
bad
);
assert!(
!is_invalid(good),
"{:08X} canonical DUP-imm should decode",
good
);
assert_eq!(mnem(good), "mov");
assert_roundtrip(good);
}
}
#[test]
fn sve_arith_imm_b_shift_reserved() {
for &(bad, good) in &[
(0x2521E415u32, 0x2521C415u32), (0x2520E415, 0x2520C415), (0x2527E415, 0x2527C415), ] {
assert!(
is_invalid(bad),
"{:08X} arith-imm .b+shift should be Invalid",
bad
);
assert!(
!is_invalid(good),
"{:08X} canonical .b no-shift arith-imm should decode",
good
);
assert_roundtrip(good);
}
}
#[test]
fn sve_arith_imm_shift_other_sizes_preserved() {
for &w in &[
0x2561E415u32, 0x25A1E415, 0x25E1E415, ] {
assert!(
!is_invalid(w),
"{:08X} shifted .h/.s/.d arith-imm should decode",
w
);
assert_roundtrip(w);
}
}
#[test]
fn sve_movprfx_reserved() {
for &(bad, good) in &[
(0x0425BFA0u32, 0x0420BFA0u32), (0x0421BFA0, 0x0420BFA0), (0x043FBFA0, 0x0420BFA0), ] {
assert!(
is_invalid(bad),
"{:08X} MOVPRFX <20:16>!=0 should be Invalid",
bad
);
assert!(
!is_invalid(good),
"{:08X} canonical MOVPRFX should decode",
good
);
assert_eq!(mnem(good), "movprfx");
assert_roundtrip(good);
}
}
#[test]
fn fp16_two_reg_misc_sz_reserved() {
for &(bad, good) in &[
(0x0E39AA68u32, 0x0E79AA68u32), (0x2E39AA68, 0x2E79AA68), (0x0EB8FA68, 0x0EF8FA68), ] {
assert!(
is_invalid(bad),
"{:08X} FP16-misc <22>==0 should be Invalid",
bad
);
assert!(
!is_invalid(good),
"{:08X} canonical FP16-misc should decode",
good
);
assert_roundtrip(good);
}
}
#[test]
fn fp16_two_reg_misc_no_fp16_opcodes_reserved() {
for &bad in &[
0x0E79EA68u32, 0x0E79FA68, 0x2E79EA68, 0x2E79FA68, 0x0EF9CA68, 0x2EF9CA68, ] {
assert!(
is_invalid(bad),
"{:08X} FP16-misc with no FP16 form should be Invalid",
bad
);
}
}
#[test]
fn fp16_two_reg_misc_valid_set_preserved() {
for &w in &[
0x0E798A68u32, 0x0E79BA68, 0x0E79DA68, 0x0EF8CA68, 0x0EF9DA68, 0x2EF8FA68, 0x2EF9FA68, ] {
assert!(!is_invalid(w), "{:08X} valid FP16-misc should decode", w);
assert_roundtrip(w);
}
}
#[test]
fn sve_pmov_to_vector_bit9_reserved() {
for &(bad, good) in &[
(0x05ED3AF7u32, 0x05ED38F7u32), (0x056D3A65, 0x056D3865), ] {
assert!(
is_invalid(bad),
"{:08X} PMOV-to-vector <9>=1 should be Invalid",
bad
);
assert!(
!is_invalid(good),
"{:08X} canonical PMOV should decode",
good
);
assert_eq!(mnem(good), "pmov");
assert_roundtrip(good);
}
}
#[test]
fn sve_pmov_from_vector_bit9_preserved() {
for &w in &[
0x05EC3AE7u32, 0x05EC38E7, ] {
assert!(!is_invalid(w), "{:08X} PMOV-from-vector should decode", w);
assert_roundtrip(w);
}
}
#[test]
fn ls64_rt_reserved() {
for &bad in &[
0xF83DA0BAu32, 0xF83AA0A1, 0xF83AA0B8, 0xF83FD0B8, 0xF83F90B8, 0xF83AB0B8, ] {
assert!(
is_invalid(bad),
"{:08X} LS64 Rt invalid should be Invalid",
bad
);
}
}
#[test]
fn ls64_valid_rt_preserved() {
for &w in &[
0xF83AA0A0u32, 0xF83AA0B6, 0xF83FD0A0, 0xF83F90A0, 0xF83AB0A0, ] {
assert!(!is_invalid(w), "{:08X} valid LS64 should decode", w);
assert_roundtrip(w);
}
}
#[test]
fn ls64_gated_by_feature() {
let no_ls64 = FeatureSet::BASE.with(Feature::Lse);
for &w in &[0xF83AA0A0u32, 0xF83FD0A0, 0xF83F90A0, 0xF83AB0A0] {
assert!(
decode(w, 0, no_ls64).is_invalid(),
"{:08X} must be gated by FEAT_LS64",
w
);
}
}