use crate::solver::{CheckOutcome, new_solver};
use crate::term::{BV, Bool};
use crate::wasm_semantics::WasmSemantics;
use std::collections::{HashMap, HashSet};
use synth_core::WasmOp;
use synth_core::wsc_facts::{FactKind, WscFact};
#[derive(Debug)]
pub struct FactSpecResult {
pub ops: Vec<WasmOp>,
pub block_arity: Vec<(u8, u8)>,
pub kept: Vec<usize>,
pub admitted: Vec<String>,
pub declined: Vec<String>,
pub elide_div_zero: Vec<usize>,
pub elide_div_ovf: Vec<usize>,
stream_changed: bool,
}
impl FactSpecResult {
pub fn changed(&self) -> bool {
self.stream_changed
}
}
#[derive(Clone)]
struct Val {
bv: BV,
start: Option<usize>,
created: usize,
}
pub fn specialize_function(
func_name: &str,
ops: &[WasmOp],
block_arity: &[(u8, u8)],
facts: &[WscFact],
params_i64: &[bool],
) -> FactSpecResult {
let mut pass = Pass::new(func_name, ops, block_arity, facts, params_i64);
pass.walk();
pass.finish()
}
#[cfg(debug_assertions)]
fn force_admit_unsound() -> bool {
std::env::var("SYNTH_FACT_SPEC_FORCE_ADMIT").is_ok_and(|v| v != "0")
}
#[cfg(not(debug_assertions))]
fn force_admit_unsound() -> bool {
false
}
struct Pass<'a> {
func: &'a str,
ops: &'a [WasmOp],
block_arity: &'a [(u8, u8)],
opener_ordinal: HashMap<usize, usize>,
range_facts: HashMap<usize, (i64, i64)>,
nonzero_facts: HashSet<usize>,
params_i64: &'a [bool],
sem: WasmSemantics,
stack: Vec<Val>,
locals: HashMap<u32, BV>,
vars: Vec<BV>,
fresh: u32,
premises: Vec<Bool>,
premise_desc: Vec<String>,
deletions: Vec<(usize, usize)>,
admitted: Vec<String>,
declined: Vec<String>,
zero_marks: Vec<usize>,
ovf_marks: Vec<usize>,
}
impl<'a> Pass<'a> {
fn new(
func: &'a str,
ops: &'a [WasmOp],
block_arity: &'a [(u8, u8)],
facts: &'a [WscFact],
params_i64: &'a [bool],
) -> Self {
let mut opener_ordinal = HashMap::new();
let mut ord = 0usize;
for (i, op) in ops.iter().enumerate() {
if matches!(op, WasmOp::Block | WasmOp::Loop | WasmOp::If) {
opener_ordinal.insert(i, ord);
ord += 1;
}
}
let mut range_facts = HashMap::new();
let mut nonzero_facts = HashSet::new();
for f in facts {
if (f.value_id as usize) >= ops.len() {
continue;
}
match f.kind {
FactKind::ValueRange { lo, hi } => {
if lo <= hi {
range_facts.insert(f.value_id as usize, (lo, hi));
}
}
FactKind::DivisorNonZero => {
nonzero_facts.insert(f.value_id as usize);
}
_ => {}
}
}
Self {
func,
ops,
block_arity,
opener_ordinal,
range_facts,
nonzero_facts,
params_i64,
sem: WasmSemantics::new_with_memory(Vec::new()),
stack: Vec::new(),
locals: HashMap::new(),
vars: Vec::new(),
fresh: 0,
premises: Vec::new(),
premise_desc: Vec::new(),
deletions: Vec::new(),
admitted: Vec::new(),
declined: Vec::new(),
zero_marks: Vec::new(),
ovf_marks: Vec::new(),
}
}
fn fresh_var(&mut self, name: String) -> BV {
let v = BV::new_const(name, 32);
self.vars.push(v.clone());
v
}
fn local_bv(&mut self, idx: u32) -> BV {
if let Some(bv) = self.locals.get(&idx) {
return bv.clone();
}
let width = if self.params_i64.get(idx as usize).copied().unwrap_or(false) {
64
} else {
32
};
let v = BV::new_const(format!("fs_l{idx}"), width);
self.vars.push(v.clone());
self.locals.insert(idx, v.clone());
v
}
fn attach_fact(&mut self, i: usize, bv: &BV) {
let width = bv.get_size();
if let Some(&(lo, hi)) = self.range_facts.get(&i) {
let (lo, hi) = if width == 32 {
(
lo.clamp(i64::from(i32::MIN), i64::from(i32::MAX)),
hi.clamp(i64::from(i32::MIN), i64::from(i32::MAX)),
)
} else {
(lo, hi)
};
let lo_bv = BV::from_i64(lo, width);
let hi_bv = BV::from_i64(hi, width);
let p = Bool::and(&[&bv.bvsge(&lo_bv), &bv.bvsle(&hi_bv)]);
self.premises.push(p);
self.premise_desc
.push(format!("value(op#{i}) ∈ [{lo}, {hi}] (signed, i{width})"));
}
if self.nonzero_facts.contains(&i) {
let p = bv.ne(BV::from_i64(0, width));
self.premises.push(p);
self.premise_desc
.push(format!("value(op#{i}) ≠ 0 (i{width})"));
}
}
fn push(&mut self, bv: BV, start: Option<usize>, created: usize) {
self.stack.push(Val { bv, start, created });
}
fn matching_end(&self, i: usize) -> Option<(usize, bool)> {
let mut depth = 0usize;
let mut has_else = false;
for (j, op) in self.ops.iter().enumerate().skip(i + 1) {
match op {
WasmOp::Block | WasmOp::Loop | WasmOp::If => depth += 1,
WasmOp::Else if depth == 0 => has_else = true,
WasmOp::End => {
if depth == 0 {
return Some((j, has_else));
}
depth -= 1;
}
_ => {}
}
}
None
}
fn havoc_region(&mut self, i: usize, end: usize, arity: (u8, u8)) {
let ops = self.ops;
for op in &ops[i + 1..end] {
if let WasmOp::LocalSet(idx) | WasmOp::LocalTee(idx) = op {
let n = self.fresh;
self.fresh += 1;
let v = self.fresh_var(format!("fs_h{n}"));
self.locals.insert(*idx, v);
}
}
for _ in 0..arity.0 {
self.stack.pop();
}
for k in 0..arity.1 {
let n = self.fresh;
self.fresh += 1;
let v = self.fresh_var(format!("fs_r{n}_{k}"));
self.push(v, None, end);
}
}
fn decline(&mut self, msg: String) {
self.declined
.push(format!("{}: {} — general lowering emitted", self.func, msg));
}
fn try_elide_div_guards(&mut self, i: usize, op_name: &str, is_div_s: bool, a: &Val, b: &Val) {
let width = b.bv.get_size();
if self.premises.is_empty() {
self.decline(format!(
"op#{i} {op_name} — no premise reaches this site; both trap guards retained"
));
return;
}
let mut solver = new_solver();
for p in &self.premises {
solver.assert(p);
}
solver.assert(&b.bv.eq(BV::from_i64(0, width)));
match solver.check() {
CheckOutcome::Unsat => {
self.zero_marks.push(i);
self.admitted.push(format!(
"{}: op#{i} {op_name} — divide-by-zero guard elided: UNSAT(P ∧ divisor == 0) via {} (certificate-checked QF_BV; every Unsat carries an LRAT proof validated by ordeal-lrat); P = {{{}}}; divisor = {}",
self.func,
solver.name(),
self.premise_desc.join(" ∧ "),
b.bv,
));
}
CheckOutcome::Sat => {
let cex = self.counterexample(solver.as_ref());
if force_admit_unsound() {
self.zero_marks.push(i);
self.admitted.push(format!(
"{}: op#{i} {op_name} — divide-by-zero guard elided by UNSOUND FORCED ADMIT (SYNTH_FACT_SPEC_FORCE_ADMIT, red-team oracle lever, debug builds only) — obligation was Sat (counterexample: {cex}); NEVER use in production",
self.func,
));
} else {
self.decline(format!(
"op#{i} {op_name} — zero-guard obligation Sat (divisor can be 0 under P; counterexample: {cex}); guard retained"
));
}
}
CheckOutcome::Unknown(reason) => {
self.decline(format!(
"op#{i} {op_name} — zero-guard obligation Unknown ({reason}); conservative decline, guard retained"
));
}
}
if !is_div_s {
return;
}
let int_min = if width == 64 {
i64::MIN
} else {
i64::from(i32::MIN)
};
let mut solver = new_solver();
for p in &self.premises {
solver.assert(p);
}
solver.assert(&a.bv.eq(BV::from_i64(int_min, width)));
solver.assert(&b.bv.eq(BV::from_i64(-1, width)));
match solver.check() {
CheckOutcome::Unsat => {
self.ovf_marks.push(i);
self.admitted.push(format!(
"{}: op#{i} {op_name} — INT{width}_MIN/-1 overflow guard elided: UNSAT(P ∧ dividend == INT{width}_MIN ∧ divisor == -1) via {} (certificate-checked QF_BV; every Unsat carries an LRAT proof validated by ordeal-lrat); P = {{{}}}",
self.func,
solver.name(),
self.premise_desc.join(" ∧ "),
));
}
CheckOutcome::Sat => {
let cex = self.counterexample(solver.as_ref());
self.decline(format!(
"op#{i} {op_name} — overflow-guard obligation Sat (dividend == INT{width}_MIN with divisor == -1 is possible under P; counterexample: {cex}); the #633 overflow guard is RETAINED — a divisor-nonzero premise alone never elides it"
));
}
CheckOutcome::Unknown(reason) => {
self.decline(format!(
"op#{i} {op_name} — overflow-guard obligation Unknown ({reason}); conservative decline, the #633 overflow guard is RETAINED"
));
}
}
}
fn counterexample(&self, solver: &dyn crate::solver::BvSolver) -> String {
let cex: Vec<String> = self
.vars
.iter()
.filter_map(|v| {
let name = format!("{v}");
solver.value(v).map(|x| {
if v.get_size() == 64 {
format!("{name}={}", x as u64 as i64)
} else {
format!("{name}={}", x as u32 as i32)
}
})
})
.collect();
if cex.is_empty() {
"<no model>".to_string()
} else {
cex.join(", ")
}
}
fn try_elide(&mut self, i: usize, end: usize, cond: &Val) -> bool {
if self.premises.is_empty() {
self.decline(format!(
"op#{i} `if` — no premise reaches this site (no usable value-range fact)"
));
return false;
}
let mut solver = new_solver();
for p in &self.premises {
solver.assert(p);
}
let taken = cond.bv.ne(BV::from_i64(0, 32));
solver.assert(&taken);
match solver.check() {
CheckOutcome::Unsat => {
let Some(start) = cond.start else {
self.decline(format!(
"op#{i} `if` proven dead (UNSAT) but its condition slice is not \
erasable (impure or non-contiguous producer)"
));
return false;
};
self.deletions.push((start, end));
self.admitted.push(format!(
"{}: op#{i} `if` (+condition slice) — ops [{start}..={end}] elided \
({} ops): UNSAT(P ∧ cond ≠ 0) via {} (certificate-checked QF_BV; \
every Unsat carries an LRAT proof validated by ordeal-lrat); \
P = {{{}}}; cond = {}",
self.func,
end - start + 1,
solver.name(),
self.premise_desc.join(" ∧ "),
cond.bv,
));
true
}
CheckOutcome::Sat => {
let cex: Vec<String> = self
.vars
.iter()
.filter_map(|v| {
let name = format!("{v}");
solver
.value(v)
.map(|x| format!("{name}={}", x as u32 as i32))
})
.collect();
self.decline(format!(
"op#{i} `if` — obligation Sat (branch reachable under P; \
counterexample: {})",
if cex.is_empty() {
"<no model>".to_string()
} else {
cex.join(", ")
}
));
false
}
CheckOutcome::Unknown(reason) => {
self.decline(format!(
"op#{i} `if` — obligation Unknown ({reason}); conservative decline"
));
false
}
}
}
fn walk(&mut self) {
if self.range_facts.is_empty() && self.nonzero_facts.is_empty() {
self.decline(
"no usable value-range or divisor-nonzero fact targets this function".to_string(),
);
return;
}
let ops = self.ops;
let mut i = 0usize;
while i < ops.len() {
let op = &ops[i];
match op {
WasmOp::Nop => {}
WasmOp::I32Const(v) => {
let bv = self.sem.encode_op(&WasmOp::I32Const(*v), &[]);
self.attach_fact(i, &bv);
self.push(bv, Some(i), i);
}
WasmOp::I64Const(v) => {
let bv = self.sem.encode_op(&WasmOp::I64Const(*v), &[]);
self.attach_fact(i, &bv);
self.push(bv, Some(i), i);
}
WasmOp::LocalGet(idx) => {
let bv = self.local_bv(*idx);
self.attach_fact(i, &bv);
self.push(bv, Some(i), i);
}
WasmOp::LocalSet(idx) => {
let Some(v) = self.stack.pop() else {
self.decline(format!("op#{i} local.set on empty symbolic stack"));
return;
};
self.locals.insert(*idx, v.bv);
}
WasmOp::LocalTee(idx) => {
let Some(top) = self.stack.last_mut() else {
self.decline(format!("op#{i} local.tee on empty symbolic stack"));
return;
};
top.start = None;
top.created = i;
let bv = top.bv.clone();
self.locals.insert(*idx, bv.clone());
self.attach_fact(i, &bv);
}
WasmOp::Drop => {
if self.stack.pop().is_none() {
self.decline(format!("op#{i} drop on empty symbolic stack"));
return;
}
}
WasmOp::I32Eqz => {
let Some(a) = self.stack.pop() else {
self.decline(format!("op#{i} unary op on empty symbolic stack"));
return;
};
if a.bv.get_size() != 32 {
self.decline(format!("op#{i} i32.eqz on a non-32-bit operand"));
return;
}
let bv = self.sem.encode_op(op, &[a.bv]);
self.attach_fact(i, &bv);
let start = a.start.filter(|_| a.created + 1 == i);
self.push(bv, start, i);
}
WasmOp::I32Add
| WasmOp::I32Sub
| WasmOp::I32Mul
| WasmOp::I32And
| WasmOp::I32Or
| WasmOp::I32Xor
| WasmOp::I32Shl
| WasmOp::I32ShrS
| WasmOp::I32ShrU
| WasmOp::I32Rotl
| WasmOp::I32Rotr
| WasmOp::I32Eq
| WasmOp::I32Ne
| WasmOp::I32LtS
| WasmOp::I32LtU
| WasmOp::I32LeS
| WasmOp::I32LeU
| WasmOp::I32GtS
| WasmOp::I32GtU
| WasmOp::I32GeS
| WasmOp::I32GeU => {
let (Some(b), Some(a)) = (self.stack.pop(), self.stack.pop()) else {
self.decline(format!("op#{i} binop on underflowing symbolic stack"));
return;
};
if a.bv.get_size() != 32 || b.bv.get_size() != 32 {
self.decline(format!("op#{i} i32 binop on a non-32-bit operand"));
return;
}
let bv = self.sem.encode_op(op, &[a.bv, b.bv]);
self.attach_fact(i, &bv);
let start = match (a.start, b.start) {
(Some(sa), Some(sb)) if a.created + 1 == sb && b.created + 1 == i => {
Some(sa)
}
_ => None,
};
self.push(bv, start, i);
}
WasmOp::I32DivU
| WasmOp::I32DivS
| WasmOp::I32RemU
| WasmOp::I32RemS
| WasmOp::I64DivU
| WasmOp::I64DivS
| WasmOp::I64RemU
| WasmOp::I64RemS => {
let (Some(b), Some(a)) = (self.stack.pop(), self.stack.pop()) else {
self.decline(format!("op#{i} div/rem on underflowing symbolic stack"));
return;
};
let (op_name, expect, is_div_s) = match op {
WasmOp::I32DivU => ("i32.div_u", 32, false),
WasmOp::I32DivS => ("i32.div_s", 32, true),
WasmOp::I32RemU => ("i32.rem_u", 32, false),
WasmOp::I32RemS => ("i32.rem_s", 32, false),
WasmOp::I64DivU => ("i64.div_u", 64, false),
WasmOp::I64DivS => ("i64.div_s", 64, true),
WasmOp::I64RemU => ("i64.rem_u", 64, false),
_ => ("i64.rem_s", 64, false),
};
if a.bv.get_size() != expect || b.bv.get_size() != expect {
self.decline(format!(
"op#{i} {op_name} on operands of unexpected width (symbolic widths {}/{}, expected {expect})",
a.bv.get_size(),
b.bv.get_size()
));
return;
}
self.try_elide_div_guards(i, op_name, is_div_s, &a, &b);
let n = self.fresh;
self.fresh += 1;
let v = self.fresh_var(format!("fs_d{n}"));
self.attach_fact(i, &v);
self.push(v, None, i);
}
WasmOp::If => {
let Some(cond) = self.stack.pop() else {
self.decline(format!("op#{i} `if` on empty symbolic stack"));
return;
};
if cond.bv.get_size() != 32 {
self.decline(format!("op#{i} `if` condition is not 32-bit"));
return;
}
let Some((end, has_else)) = self.matching_end(i) else {
self.decline(format!("op#{i} `if` without matching `end`"));
return;
};
let Some(&ord) = self.opener_ordinal.get(&i) else {
self.decline(format!("op#{i} `if` missing from the opener ordinal map"));
return;
};
let Some(&arity) = self.block_arity.get(ord) else {
self.decline(format!(
"op#{i} `if` has no block_arity entry (side-table desync)"
));
return;
};
if has_else {
self.decline(format!(
"op#{i} `if`/`else` — only no-else `if` is in Phase-2 scope"
));
self.havoc_region(i, end, arity);
} else if self.try_elide(i, end, &cond) {
} else {
self.havoc_region(i, end, arity);
}
i = end + 1;
continue;
}
WasmOp::End => break,
WasmOp::Return => break,
other => {
self.decline(format!(
"op#{i} {other:?} is outside the tracked i32 fragment — \
fact tracking stops here (no further elisions in this function)"
));
return;
}
}
i += 1;
}
}
fn finish(self) -> FactSpecResult {
let Pass {
ops,
block_arity,
deletions,
admitted,
declined,
zero_marks,
ovf_marks,
..
} = self;
if deletions.is_empty() {
return FactSpecResult {
ops: ops.to_vec(),
block_arity: block_arity.to_vec(),
kept: (0..ops.len()).collect(),
admitted,
declined,
elide_div_zero: zero_marks,
elide_div_ovf: ovf_marks,
stream_changed: false,
};
}
let deleted = |i: usize| deletions.iter().any(|&(s, e)| i >= s && i <= e);
let mut out_ops = Vec::with_capacity(ops.len());
let mut out_arity = Vec::with_capacity(block_arity.len());
let mut kept = Vec::with_capacity(ops.len());
let mut ord = 0usize;
for (i, op) in ops.iter().enumerate() {
let is_opener = matches!(op, WasmOp::Block | WasmOp::Loop | WasmOp::If);
if !deleted(i) {
out_ops.push(op.clone());
kept.push(i);
if is_opener && let Some(&a) = block_arity.get(ord) {
out_arity.push(a);
}
}
if is_opener {
ord += 1;
}
}
let remap = |marks: Vec<usize>| -> Vec<usize> {
marks
.into_iter()
.filter_map(|m| {
debug_assert!(!deleted(m), "guard mark op#{m} inside a deleted range");
kept.binary_search(&m).ok()
})
.collect()
};
FactSpecResult {
ops: out_ops,
block_arity: out_arity,
elide_div_zero: remap(zero_marks),
elide_div_ovf: remap(ovf_marks),
kept,
admitted,
declined,
stream_changed: true,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use WasmOp::*;
fn fact(value_id: u32, lo: i64, hi: i64) -> WscFact {
WscFact {
func_index: 0,
value_id,
kind: FactKind::ValueRange { lo, hi },
}
}
fn clamp_ops() -> Vec<WasmOp> {
vec![
LocalGet(0), I32Const(476), I32Add, LocalSet(1), LocalGet(1), I32Const(1000), I32LtS, If, I32Const(1000), LocalSet(1), End, LocalGet(1), I32Const(2000), I32GtS, If, I32Const(2000), LocalSet(1), End, LocalGet(1), End, ]
}
const CLAMP_ARITY: &[(u8, u8)] = &[(0, 0), (0, 0)];
#[test]
fn clamp_shape_elides_both_branches_under_the_proven_bound_494() {
let ops = clamp_ops();
let r = specialize_function("gust_mix", &ops, CLAMP_ARITY, &[fact(0, 524, 1524)], &[]);
assert_eq!(r.admitted.len(), 2, "declines: {:?}", r.declined);
assert!(r.changed());
assert_eq!(
r.ops,
vec![
LocalGet(0),
I32Const(476),
I32Add,
LocalSet(1),
LocalGet(1),
End
],
"both clamp comparisons + branches + bodies must be gone"
);
assert_eq!(r.block_arity, vec![], "both If arity entries removed");
assert_eq!(r.kept, vec![0, 1, 2, 3, 18, 19]);
for line in &r.admitted {
assert!(line.contains("UNSAT"), "{line}");
assert!(line.contains("certificate-checked"), "{line}");
assert!(line.contains("[524, 1524]"), "{line}");
}
}
#[test]
fn wrong_wide_bound_is_sat_and_declines_loudly_494() {
let ops = clamp_ops();
let r = specialize_function("gust_mix", &ops, CLAMP_ARITY, &[fact(0, 0, 4000)], &[]);
assert_eq!(r.admitted.len(), 0);
assert!(!r.changed());
assert_eq!(r.ops, ops, "declined ⇒ byte-identical op stream");
assert_eq!(r.block_arity, CLAMP_ARITY.to_vec());
assert!(
r.declined
.iter()
.any(|d| d.contains("Sat") && d.contains("counterexample")),
"declines must be loud and carry a model: {:?}",
r.declined
);
}
#[test]
fn partially_dead_bound_elides_only_the_proven_branch_494() {
let ops = clamp_ops();
let r = specialize_function("gust_mix", &ops, CLAMP_ARITY, &[fact(0, 524, 4000)], &[]);
assert_eq!(r.admitted.len(), 1, "declines: {:?}", r.declined);
assert_eq!(r.declined.len(), 1);
assert_eq!(
r.ops,
vec![
LocalGet(0),
I32Const(476),
I32Add,
LocalSet(1),
LocalGet(1),
I32Const(2000),
I32GtS,
If,
I32Const(2000),
LocalSet(1),
End,
LocalGet(1),
End,
]
);
assert_eq!(r.block_arity, vec![(0, 0)], "one If survives");
}
#[test]
fn no_facts_changes_nothing_494() {
let ops = clamp_ops();
let r = specialize_function("gust_mix", &ops, CLAMP_ARITY, &[], &[]);
assert!(!r.changed());
assert_eq!(r.ops, ops);
assert!(!r.declined.is_empty(), "the no-fact case is a loud decline");
}
#[test]
fn declined_if_havocs_its_locals_no_false_admit_downstream_494() {
let ops = vec![
LocalGet(0), I32Const(476), I32Add, LocalSet(1), LocalGet(2), If, I32Const(-9), LocalSet(1), End, LocalGet(1), I32Const(2000), I32GtS, If, I32Const(2000), LocalSet(1), End, LocalGet(1), End, ];
let r = specialize_function("f", &ops, CLAMP_ARITY, &[fact(0, 524, 1524)], &[]);
assert_eq!(
r.admitted.len(),
0,
"havocked local must block the downstream elision: {:?}",
r.admitted
);
assert_eq!(r.ops, ops);
}
#[test]
fn if_with_else_declines_494() {
let ops = vec![
LocalGet(0), If, I32Const(1), LocalSet(1), Else, I32Const(2), LocalSet(1), End, LocalGet(1), End, ];
let r = specialize_function("f", &ops, &[(0, 0)], &[fact(0, 0, 0)], &[]);
assert_eq!(r.admitted.len(), 0);
assert!(
r.declined.iter().any(|d| d.contains("else")),
"{:?}",
r.declined
);
assert_eq!(r.ops, ops);
}
#[test]
fn nested_opener_inside_elided_body_fixes_block_arity_ordinals_494() {
let ops = vec![
LocalGet(0), I32Eqz, If, LocalGet(0), If, I32Const(7), LocalSet(1), End, End, Block, End, End, ];
let arity = &[(0, 0), (0, 0), (0, 1)];
let r = specialize_function("f", &ops, arity, &[fact(0, 5, 5)], &[]);
assert_eq!(r.admitted.len(), 1, "declines: {:?}", r.declined);
assert_eq!(r.ops, vec![Block, End, End]);
assert_eq!(r.kept, vec![9, 10, 11]);
assert_eq!(
r.block_arity,
vec![(0, 1)],
"only the surviving Block's entry"
);
}
#[test]
fn tee_condition_slice_is_not_erasable_494() {
let ops = vec![
LocalGet(0), LocalTee(1), I32Eqz, If, I32Const(9), LocalSet(2), End, End, ];
let r = specialize_function("f", &ops, &[(0, 0)], &[fact(0, 1, 1)], &[]);
assert_eq!(r.admitted.len(), 0);
assert!(
r.declined
.iter()
.any(|d| d.contains("not") && d.contains("erasable")),
"{:?}",
r.declined
);
assert_eq!(r.ops, ops);
}
#[test]
fn untracked_op_stops_tracking_loudly_494() {
let ops = vec![
LocalGet(0), I64ExtendI32S, Drop, End, ];
let r = specialize_function("f", &ops, &[], &[fact(0, 1, 2)], &[]);
assert!(!r.changed());
assert!(
r.declined.iter().any(|d| d.contains("outside the tracked")),
"{:?}",
r.declined
);
}
fn nonzero_fact(value_id: u32) -> WscFact {
WscFact {
func_index: 0,
value_id,
kind: FactKind::DivisorNonZero,
}
}
#[test]
fn divisor_range_excluding_zero_elides_zero_guard_all_rem_div_494() {
let ops = vec![
LocalGet(0), LocalGet(1), I32DivU, Drop, LocalGet(0), LocalGet(1), I32RemU, Drop, LocalGet(0), LocalGet(1), I32RemS, End, ];
let facts = [fact(1, 1, 100), fact(5, 1, 100), fact(9, 1, 100)];
let r = specialize_function("f", &ops, &[], &facts, &[]);
assert_eq!(
r.elide_div_zero,
vec![2, 6, 10],
"declines: {:?}",
r.declined
);
assert_eq!(
r.elide_div_ovf,
Vec::<usize>::new(),
"no div_s in the stream"
);
assert!(!r.changed(), "guard marks never rewrite the op stream");
assert_eq!(r.ops, ops);
assert_eq!(r.admitted.len(), 3);
for line in &r.admitted {
assert!(line.contains("divide-by-zero guard elided"), "{line}");
assert!(line.contains("UNSAT(P ∧ divisor == 0)"), "{line}");
assert!(line.contains("certificate-checked"), "{line}");
}
}
#[test]
fn nonzero_fact_elides_zero_guard_but_retains_div_s_overflow_guard_494() {
let ops = vec![
LocalGet(0), LocalGet(1), I32DivS, End, ];
let r = specialize_function("f", &ops, &[], &[nonzero_fact(1)], &[]);
assert_eq!(r.elide_div_zero, vec![2], "declines: {:?}", r.declined);
assert_eq!(
r.elide_div_ovf,
Vec::<usize>::new(),
"divisor ≠ 0 must NOT elide the INT_MIN/-1 overflow guard"
);
assert!(
r.declined
.iter()
.any(|d| d.contains("overflow-guard obligation Sat") && d.contains("RETAINED")),
"{:?}",
r.declined
);
}
#[test]
fn positive_range_discharges_both_div_s_obligations_494() {
let ops = vec![LocalGet(0), LocalGet(1), I32DivS, End];
let r = specialize_function("f", &ops, &[], &[fact(1, 1, 100)], &[]);
assert_eq!(r.elide_div_zero, vec![2], "declines: {:?}", r.declined);
assert_eq!(r.elide_div_ovf, vec![2]);
assert_eq!(r.admitted.len(), 2, "one certificate line per obligation");
assert!(
r.admitted
.iter()
.any(|a| a.contains("overflow guard elided")
&& a.contains("dividend == INT32_MIN ∧ divisor == -1")),
"{:?}",
r.admitted
);
}
#[test]
fn range_including_zero_is_sat_and_declines_the_zero_guard_494() {
let ops = vec![LocalGet(0), LocalGet(1), I32DivU, End];
let r = specialize_function("f", &ops, &[], &[fact(1, 0, 100)], &[]);
assert_eq!(r.elide_div_zero, Vec::<usize>::new());
assert!(
r.declined
.iter()
.any(|d| d.contains("zero-guard obligation Sat") && d.contains("counterexample")),
"{:?}",
r.declined
);
}
#[test]
fn i64_div_s_nonzero_fact_zero_guard_only_overflow_retained_494() {
let ops = vec![LocalGet(0), LocalGet(1), I64DivS, End];
let r = specialize_function("f", &ops, &[], &[nonzero_fact(1)], &[true, true]);
assert_eq!(r.elide_div_zero, vec![2], "declines: {:?}", r.declined);
assert_eq!(
r.elide_div_ovf,
Vec::<usize>::new(),
"i64 overflow guard retained"
);
assert!(
r.declined.iter().any(|d| d.contains("RETAINED")),
"{:?}",
r.declined
);
}
#[test]
fn i64_div_s_positive_range_discharges_both_obligations_494() {
let ops = vec![LocalGet(0), LocalGet(1), I64DivS, End];
let r = specialize_function("f", &ops, &[], &[fact(1, 1, 1000)], &[true, true]);
assert_eq!(r.elide_div_zero, vec![2], "declines: {:?}", r.declined);
assert_eq!(r.elide_div_ovf, vec![2]);
}
#[test]
fn i64_div_on_undeclared_width_declines_no_marks_494() {
let ops = vec![LocalGet(0), LocalGet(1), I64DivU, End];
let r = specialize_function("f", &ops, &[], &[nonzero_fact(1)], &[]);
assert_eq!(r.elide_div_zero, Vec::<usize>::new());
assert!(
r.declined.iter().any(|d| d.contains("unexpected width")),
"{:?}",
r.declined
);
}
#[test]
fn div_with_no_premise_declines_loudly_494() {
let ops = vec![
LocalGet(0), LocalGet(1), I32DivU, End, ];
let r = specialize_function("f", &ops, &[], &[fact(0, 1, 5)], &[]);
assert_eq!(r.elide_div_zero, Vec::<usize>::new());
assert!(
r.declined
.iter()
.any(|d| d.contains("zero-guard obligation Sat")),
"{:?}",
r.declined
);
}
#[test]
fn guard_marks_are_remapped_through_a_clamp_elision_494() {
let ops = vec![
LocalGet(0), I32Const(476), I32Add, LocalSet(1), LocalGet(1), I32Const(1000), I32LtS, If, I32Const(1000), LocalSet(1), End, LocalGet(1), LocalGet(0), I32DivU, End, ];
let r = specialize_function("f", &ops, &[(0, 0)], &[fact(0, 524, 1524)], &[]);
assert!(r.changed(), "declines: {:?}", r.declined);
assert_eq!(r.kept, vec![0, 1, 2, 3, 11, 12, 13, 14]);
assert_eq!(
r.ops,
vec![
LocalGet(0),
I32Const(476),
I32Add,
LocalSet(1),
LocalGet(1),
LocalGet(0),
I32DivU,
End
]
);
assert_eq!(
r.elide_div_zero,
vec![6],
"mark remapped from original op#13 to rewritten op#6"
);
}
#[test]
fn out_of_range_value_id_is_vacuous_494() {
let ops = clamp_ops();
let r = specialize_function("f", &ops, CLAMP_ARITY, &[fact(999, 524, 1524)], &[]);
assert!(!r.changed());
assert_eq!(r.ops, ops);
}
}