use iced_x86::Instruction;
use crate::c::c_one;
use crate::image::{Image, Segment};
use crate::runtime::RuntimeMap;
use crate::scan::decode;
use crate::wide_alu::op_byte_width;
fn run_fn(bytes: &[u8]) -> String {
let mut data = vec![0xccu8; 0x100];
data[..bytes.len()].copy_from_slice(bytes);
let img = Image {
data,
segments: vec![Segment { va: 0x1000, offset: 0, size: 0x100 }],
functions: std::iter::once(0x1000..0x1000 + bytes.len() as u64).collect(),
pointers: Vec::new(),
imports: Vec::new(),
symbols: Vec::new(),
metadata: crate::image_format::Metadata::default(),
};
let rt = RuntimeMap::detect(&img);
c_one(&img, &[], &rt, 0x1000, None, None).unwrap_or_default().1
}
#[test]
fn covers_all_widening_mul_div_and_sign_extension_widths() {
let imul8 = run_fn(&[0x48, 0x89, 0xf0, 0x40, 0xf6, 0xef, 0xc3]);
assert!(imul8.contains("(i16)(i8)"));
let imul16 = run_fn(&[0x48, 0x89, 0xf0, 0x66, 0xf7, 0xef, 0x66, 0x01, 0xd0, 0xc3]);
assert!(imul16.contains("prod_") && imul16.contains("(i32)(i16)"));
let mul32_both = run_fn(&[0x89, 0xf0, 0xf7, 0xe7, 0x01, 0xd0, 0xc3]);
assert!(mul32_both.contains("prod_") && mul32_both.contains("(u64)(u32)"));
let imul32_lo = run_fn(&[0x89, 0xf0, 0xf7, 0xef, 0x31, 0xd2, 0xc3]);
assert!(imul32_lo.contains("(u32)"));
let mul64_lo = run_fn(&[0x48, 0x89, 0xf0, 0x48, 0xf7, 0xe7, 0x48, 0x83, 0xc0, 0x01, 0x31, 0xd2, 0xc3]);
assert!(mul64_lo.contains('*'));
let imul64_both = run_fn(&[0x48, 0x89, 0xf0, 0x48, 0xf7, 0xef, 0x48, 0x01, 0xd0, 0xc3]);
assert!(imul64_both.contains("i128 prod_"));
let mul_hi_only = run_fn(&[0x48, 0x89, 0xf0, 0x48, 0xf7, 0xe7, 0x48, 0x89, 0xd0, 0xc3]);
assert!(mul_hi_only.contains(">> 64"));
let mul_dead = run_fn(&[0x48, 0x89, 0xf0, 0x48, 0xf7, 0xe7, 0x0f, 0x92, 0xc0, 0x0f, 0xb6, 0xc0, 0x31, 0xd2, 0xc3]);
assert!(mul_dead.contains("umul_overflow"));
let idiv8 = run_fn(&[0x89, 0xf0, 0x40, 0xf6, 0xff, 0xc3]);
assert!(idiv8.contains("(i16)(i8)"));
let div8 = run_fn(&[0xb8, 0x07, 0x00, 0x34, 0x12, 0xb1, 0x03, 0xf6, 0xf1, 0xc3]);
assert!(div8.contains("& ~0xffff") && div8.contains("<< 8"));
let div16_z = run_fn(&[0x31, 0xd2, 0x89, 0xf0, 0x66, 0xf7, 0xf7, 0x66, 0x01, 0xd0, 0xc3]);
assert!(div16_z.contains("(u16)"));
let div32_z = run_fn(&[0x31, 0xd2, 0x89, 0xf0, 0xf7, 0xf7, 0x01, 0xd0, 0xc3]);
assert!(div32_z.contains("((u32)arg_1 / (u32)arg_0)"), "{div32_z}");
let div64_z = run_fn(&[0x31, 0xd2, 0x48, 0x89, 0xf0, 0x48, 0xf7, 0xf7, 0x48, 0x01, 0xd0, 0xc3]);
assert!(div64_z.contains("((u64)arg_1 / (u64)arg_0)"), "{div64_z}");
let idiv16_sext = run_fn(&[0x31, 0xd2, 0x89, 0xf0, 0x66, 0x99, 0x90, 0x66, 0xf7, 0xff, 0x31, 0xd2, 0xc3]);
assert!(idiv16_sext.contains("(u16)((i16)"), "{idiv16_sext}");
let idiv32_sext = run_fn(&[0x89, 0xf0, 0x99, 0xf7, 0xff, 0xc3]);
assert!(idiv32_sext.contains("(i32)"));
let idiv64_loop =
run_fn(&[0x48, 0x89, 0xf0, 0x48, 0x99, 0x90, 0x48, 0xf7, 0xff, 0x48, 0x85, 0xd2, 0x75, 0xf5, 0xc3]);
assert!(idiv64_loop.contains("div_") && idiv64_loop.contains("% (i64)"));
let div16_w = run_fn(&[0x48, 0x89, 0xf0, 0x66, 0xf7, 0xf7, 0x31, 0xd2, 0xc3]);
assert!(div16_w.contains("(u32)"));
let idiv16_w = run_fn(&[0x48, 0x89, 0xf0, 0x66, 0xf7, 0xff, 0xc3]);
assert!(idiv16_w.contains("(i32)"));
let div32_w = run_fn(&[0x89, 0xf0, 0xf7, 0xf7, 0xc3]);
assert!(div32_w.contains("(u64)"));
let idiv32_w = run_fn(&[0x89, 0xf0, 0xf7, 0xff, 0xc3]);
assert!(idiv32_w.contains("(i64)"));
let div64_w = run_fn(&[0x48, 0x89, 0xf0, 0x48, 0xf7, 0xf7, 0x48, 0x01, 0xd0, 0xc3]);
assert!(div64_w.contains("u128 div_"));
let idiv64_lo_only = run_fn(&[0x48, 0x89, 0xf0, 0x48, 0xf7, 0xff, 0x31, 0xd2, 0xc3]);
assert!(idiv64_lo_only.contains("(i128)("), "{idiv64_lo_only}");
let sexts = run_fn(&[0x48, 0x89, 0xf8, 0x66, 0x98, 0x98, 0x48, 0x98, 0xc3]);
assert!(sexts.contains("(i64)(i32)"));
let mut jmp = Instruction::default();
decode(&[0xeb, 0x00], 0x1000, |d| jmp = *d);
assert_eq!(op_byte_width(&jmp), 8);
}