use std::collections::HashMap;
use relon_codegen_llvm::LlvmAotEvaluator;
use relon_eval_api::{Evaluator, Value};
const REM_SRC: &str = "#main(Int a, Int b) -> Int\n a % b";
fn extract_int(v: Value) -> i64 {
match v {
Value::Int(i) => i,
other => panic!("expected Int, got {other:?}"),
}
}
#[test]
fn stamped_target_cpu_equals_runtime_host() {
let host = LlvmAotEvaluator::host_target_cpu();
assert!(
!host.is_empty(),
"host CPU introspection returned empty; cannot verify the stamp"
);
let ev = LlvmAotEvaluator::from_source(REM_SRC).expect("rem kernel compiles via LLVM AOT");
let dump = ev.emit_ir_dump();
let needle = format!("\"target-cpu\"=\"{host}\"");
assert!(
dump.contains(&needle),
"post-O3 IR does not stamp the runtime host `target-cpu` ({needle}); \
dump attributes:\n{}",
dump.lines()
.filter(|l| l.contains("attributes #"))
.collect::<Vec<_>>()
.join("\n")
);
assert!(
!dump.contains("\"target-cpu\"=\"\""),
"a function was stamped with an empty target-cpu:\n{dump}"
);
}
fn has_32bit_divide(code: &[u8]) -> bool {
for i in 0..code.len() {
if code[i] != 0xF7 {
continue;
}
let Some(&modrm) = code.get(i + 1) else {
continue;
};
let reg = (modrm >> 3) & 0x7;
if reg != 6 && reg != 7 {
continue;
}
let rex_w = i > 0 && (code[i - 1] & 0xF8) == 0x48 && (code[i - 1] & 0x08) != 0;
if !rex_w {
return true;
}
}
false
}
fn has_shr_32_test(code: &[u8]) -> bool {
for w in code.windows(4) {
if w[0] == 0x48 && w[1] == 0xC1 && (w[2] >> 3) & 0x7 == 5 && w[3] == 0x20 {
return true;
}
}
false
}
#[test]
fn mcjit_rem_uses_host_divide_narrowing() {
let ev = LlvmAotEvaluator::from_source(REM_SRC).expect("rem kernel compiles via LLVM AOT");
let addr = ev
.fast_entry_runtime_addr()
.unwrap_or_else(|| ev.entry_runtime_addr());
assert!(addr != 0, "JIT did not resolve an entry address");
let code: &[u8] = unsafe { std::slice::from_raw_parts(addr as *const u8, 256) };
if !(has_32bit_divide(code) && has_shr_32_test(code)) {
eprintln!(
"[skip] host_cpu={} does not emit the SlowDivide64 idiv->divl \
narrowing for `a % b`; host-tuning fingerprint N/A here \
(correctness covered by the oracle + stamp-equals-host tests)",
LlvmAotEvaluator::host_target_cpu()
);
return;
}
assert!(has_32bit_divide(code) && has_shr_32_test(code));
}
#[test]
fn mcjit_rem_matches_rust_oracle() {
let ev = LlvmAotEvaluator::from_source(REM_SRC).expect("rem kernel compiles via LLVM AOT");
let cases: &[(i64, i64)] = &[
(10, 3),
(10, 5),
(0, 7),
(7, 7),
(1_000_003, 101),
(9_000_000_000, 7),
(-17, 5),
(17, -5),
(-17, -5),
(i64::MAX, 3),
(i64::MIN + 1, 7),
];
for &(a, b) in cases {
let mut args = HashMap::new();
args.insert("a".to_string(), Value::Int(a));
args.insert("b".to_string(), Value::Int(b));
let got = extract_int(ev.run_main(args).expect("run_main"));
assert_eq!(
got,
a % b,
"MCJIT host-codegen `a % b` diverged from Rust oracle for a={a}, b={b}"
);
}
}