use object::{Object, ObjectSection};
use std::process::Command;
fn synth() -> &'static str {
env!("CARGO_BIN_EXE_synth")
}
fn fixture(name: &str) -> std::path::PathBuf {
std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.join("scripts/repro")
.join(name)
}
fn compile_text(
fixture_name: &str,
out_tag: &str,
envs: &[(&str, &str)],
extra: &[&str],
) -> Vec<u8> {
let path = fixture(fixture_name);
let elf = format!("/tmp/volseg543_p2_{out_tag}.elf");
let mut args = vec![
"compile",
path.to_str().unwrap(),
"-o",
&elf,
"-b",
"arm",
"--target",
"cortex-m4",
"--all-exports",
];
args.extend_from_slice(extra);
let mut cmd = Command::new(synth());
for (k, v) in envs {
cmd.env(k, v);
}
let out = cmd.args(&args).output().expect("run synth");
assert!(
out.status.success(),
"synth compile failed (tag={out_tag}): exit={:?} stderr={}",
out.status.code(),
String::from_utf8_lossy(&out.stderr)
);
let bytes = std::fs::read(&elf).expect("read elf");
let obj = object::File::parse(&*bytes).expect("parse elf");
obj.section_by_name(".text")
.expect("fixture must have a .text section")
.data()
.expect("read .text")
.to_vec()
}
const FIXTURE: &str = "volatile_segment_543.wat";
const BASE_CSE: (&str, &str) = ("SYNTH_BASE_CSE", "1");
#[test]
fn base_cse_honors_volatile_window_543() {
let c = compile_text(FIXTURE, "baseline", &[], &[]);
let a = compile_text(FIXTURE, "folded", &[BASE_CSE], &[]);
let p = compile_text(
FIXTURE,
"window",
&[BASE_CSE],
&["--volatile-segment", "0x100:16"],
);
let f = compile_text(
FIXTURE,
"fullcover",
&[BASE_CSE],
&["--volatile-segment", "0x80:144"],
);
assert!(
a.len() < c.len(),
"non-vacuity: base-CSE must fire on this fixture without ranges \
(folded {} B !< baseline {} B)",
a.len(),
c.len()
);
assert!(
a.len() < p.len(),
"#543 Phase 2 RED CHECK: --volatile-segment 0x100:16 must suppress the \
folds of the 2 window stores, growing .text over the fully-folded \
form (window {} B vs folded {} B — equal means the flag is IGNORED)",
p.len(),
a.len()
);
assert!(
p.len() < c.len(),
"surgical back-off: the 2 OUTSIDE stores must still fold under a \
partial range (window {} B !< baseline {} B)",
p.len(),
c.len()
);
assert_eq!(
f, c,
"full-coverage range must fully decline base-CSE: every store \
survives verbatim, byte-identical to never enabling SYNTH_BASE_CSE"
);
}
#[test]
fn const_cse_declines_wholesale_under_volatile_543() {
const CSE: (&str, &str) = ("SYNTH_CONST_CSE", "1");
let base = compile_text("const_cse.wat", "cse_baseline", &[], &[]);
let on = compile_text("const_cse.wat", "cse_on", &[CSE], &[]);
let on_volatile = compile_text(
"const_cse.wat",
"cse_on_volatile",
&[CSE],
&["--volatile-segment", "0x100:16"],
);
assert!(
on.len() < base.len(),
"non-vacuity: const-CSE must fire on the headroom fixture \
({} B !< {} B)",
on.len(),
base.len()
);
assert_eq!(
on_volatile, base,
"#543 Phase 2 RED CHECK: with a marked volatile range const-CSE must \
decline wholesale — byte-identical to SYNTH_CONST_CSE unset (a \
difference means an aliasing rewrite still fired)"
);
}
#[test]
fn volatile_gates_are_identity_when_no_range_marked_543() {
let a1 = compile_text(FIXTURE, "id_a", &[BASE_CSE], &[]);
let a2 = compile_text(FIXTURE, "id_b", &[BASE_CSE], &[]);
assert_eq!(a1, a2, "deterministic compile");
}