mod export;
mod fp;
mod import;
mod obligation;
#[cfg(test)]
mod tests;
pub use import::{Import, import};
pub use obligation::rule_obligation;
use crate::error::Error;
use crate::expr::{Context, Expr};
use crate::facts::{Assumptions, Facts, Reliance};
pub fn export(cx: &mut Context, roots: &[Expr]) -> Result<String, Error> {
export::emit(cx, roots)
}
pub fn equivalence_query(cx: &mut Context, a: Expr, b: Expr) -> Result<String, Error> {
if cx.width(a)? != cx.width(b)? {
return Err(Error::Unsupported("different widths".into()));
}
let body = export::emit(cx, &[a, b])?;
let mut s = logic(&body);
s.push_str(&body);
s.push_str("(assert (not (= root0 root1)))\n(check-sat)\n");
Ok(s)
}
pub fn equivalence_query_under(
cx: &mut Context,
a: Expr,
b: Expr,
assumptions: &Assumptions,
relied: Reliance,
) -> Result<String, Error> {
if cx.width(a)? != cx.width(b)? {
return Err(Error::Unsupported("different widths".into()));
}
let mut roots = vec![a, b];
let mut constraints = Vec::new();
for (id, e, f) in assumptions.constraints() {
if relied.may_use(id) {
roots.push(e);
constraints.push(f);
}
}
let body = export::emit(cx, &roots)?;
let mut s = logic(&body);
s.push_str(&body);
for (k, f) in constraints.iter().enumerate() {
s.push_str(&facts_assertion(&format!("root{}", k + 2), f));
}
s.push_str("(assert (not (= root0 root1)))\n(check-sat)\n");
Ok(s)
}
fn logic(body: &str) -> String {
let uf = body.contains("(declare-fun ");
let fp = body.contains("(_ to_fp ");
String::from(match (uf, fp) {
(false, false) => "(set-logic QF_BV)\n",
(true, false) => "(set-logic QF_UFBV)\n",
(false, true) => "(set-logic QF_BVFP)\n",
(true, true) => "(set-logic ALL)\n",
})
}
fn facts_assertion(term: &str, f: &Facts) -> String {
use crate::BitVec;
let w = f.width();
let lit = export::literal;
let mut s = String::new();
let k = f.known();
if !k.known().is_zero() {
s.push_str(&format!(
"(assert (= (bvand {term} {}) {}))\n",
lit(&k.known()),
lit(&k.known_one())
));
}
let (u, sr) = (f.urange(), f.srange());
if !u.lo().is_zero() {
s.push_str(&format!("(assert (bvule {} {term}))\n", lit(&u.lo())));
}
if !u.hi().is_ones() {
s.push_str(&format!("(assert (bvule {term} {}))\n", lit(&u.hi())));
}
if sr.lo() != BitVec::smin(w) {
s.push_str(&format!("(assert (bvsle {} {term}))\n", lit(&sr.lo())));
}
if sr.hi() != BitVec::smax(w) {
s.push_str(&format!("(assert (bvsle {term} {}))\n", lit(&sr.hi())));
}
s
}