Skip to content

Commit 5f72e5e

Browse files
committed
sca: compute more statistics
1 parent 1fae366 commit 5f72e5e

File tree

2 files changed

+79
-4
lines changed

2 files changed

+79
-4
lines changed

patronus-sca/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub fn verify_word_level_equality(ctx: &mut Context, p: ScaEqualityProblem) -> S
6666
.collect();
6767

6868
// now we can perform backwards substitution
69-
let result = backwards_sub(ctx, &input_vars, gate_outputs.into(), spec);
69+
let result = backwards_sub(ctx, &input_vars, gate_outputs, p.gate_level, spec);
7070

7171
if result.is_zero() {
7272
ScaVerifyResult::Equal

patronus-sca/src/rewrite.rs

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ use patronus::expr::{
99
Context, DenseExprMetaData, DenseExprSet, Expr, ExprMap, ExprRef, ExprSet, ForEachChild,
1010
count_expr_uses, traversal,
1111
};
12+
use patronus::smt::Error::Parser;
1213
use polysub::{Coef, Mod, PhaseOptPolynom, VarIndex};
13-
use rustc_hash::FxHashSet;
14+
use rustc_hash::{FxHashMap, FxHashSet};
1415
use std::collections::VecDeque;
1516

1617
/// Used for backwards substitution
@@ -20,12 +21,20 @@ pub fn backwards_sub(
2021
ctx: &Context,
2122
input_vars: &FxHashSet<VarIndex>,
2223
todo: Vec<(VarIndex, ExprRef)>,
24+
gate_level_expr: ExprRef,
2325
spec: Poly,
2426
) -> Poly {
2527
let root_vars: Vec<_> = todo.iter().map(|(v, _)| *v).collect();
2628
let root_exprs: Vec<_> = todo.iter().map(|(_, e)| *e).collect();
2729
let root_uses = analyze_uses(ctx, &root_exprs);
2830

31+
// check to see if there are any half adders we can identify
32+
let xor_and_pairs = find_xor_and_pairs(ctx, gate_level_expr);
33+
println!("XOR/AND: {xor_and_pairs:?}");
34+
35+
let same_input = find_expr_with_same_inputs(ctx, gate_level_expr);
36+
println!("SAME INPUT: {same_input:?}");
37+
2938
// empirically, it looks like we should not use a stack
3039
let mut todo: VecDeque<_> = todo.into();
3140
let mut spec: PolyOpt = spec.into();
@@ -39,8 +48,10 @@ pub fn backwards_sub(
3948
let mut seen = DenseExprSet::default();
4049

4150
while !todo.is_empty() {
42-
let min_idx = try_exhaustive(ctx, input_vars, &spec, todo.iter().cloned(), &root_uses);
43-
let (output_var, gate) = todo.swap_remove_back(min_idx).unwrap();
51+
//let gate_idx = try_exhaustive(ctx, input_vars, &spec, todo.iter().cloned(), &root_uses);
52+
// println!("CHOICE: {todo:?}");
53+
let gate_idx = pick_smallest_use(todo.iter().cloned(), &root_uses);
54+
let (output_var, gate) = todo.swap_remove_back(gate_idx).unwrap();
4455

4556
// chose variable to replace
4657
//let (output_var, gate) = todo.pop_back().unwrap();
@@ -162,6 +173,15 @@ fn replace_gate(
162173
}
163174
}
164175

176+
fn pick_smallest_use(
177+
todo: impl Iterator<Item = (VarIndex, ExprRef)>,
178+
root_uses: &impl ExprMap<BitSet>,
179+
) -> usize {
180+
let uses: Vec<_> = todo.map(|(_, gate)| root_uses[gate].len()).collect();
181+
let min_uses = *uses.iter().min().unwrap();
182+
uses.iter().position(|u| *u == min_uses).unwrap()
183+
}
184+
165185
fn try_exhaustive(
166186
ctx: &Context,
167187
input_vars: &FxHashSet<VarIndex>,
@@ -268,3 +288,58 @@ fn analyze_uses(ctx: &Context, roots: &[ExprRef]) -> impl ExprMap<BitSet> {
268288

269289
out
270290
}
291+
292+
/// Tries to identify two expressions which correspond to "a and b" and "a xor b".
293+
fn find_xor_and_pairs(ctx: &Context, gate_level: ExprRef) -> Vec<(ExprRef, ExprRef)> {
294+
let mut xor = FxHashMap::default();
295+
let mut and = FxHashMap::default();
296+
traversal::bottom_up(ctx, gate_level, |ctx, e, _| match ctx[e].clone() {
297+
Expr::BVXor(a, b, 1) => {
298+
xor.insert(two_expr_key(a, b), e);
299+
}
300+
Expr::BVAnd(a, b, 1) => {
301+
and.insert(two_expr_key(a, b), e);
302+
}
303+
_ => {}
304+
});
305+
let mut out = vec![];
306+
for (key, xor_e) in xor.iter() {
307+
if let Some(and_e) = and.get(key) {
308+
out.push((*xor_e, *and_e));
309+
}
310+
}
311+
out
312+
}
313+
314+
fn find_expr_with_same_inputs(ctx: &Context, gate_level: ExprRef) -> Vec<(ExprRef, ExprRef)> {
315+
let mut others = FxHashMap::default();
316+
traversal::bottom_up(ctx, gate_level, |ctx, e, _| match ctx[e].clone() {
317+
Expr::BVXor(a, b, 1) | Expr::BVAnd(a, b, 1) | Expr::BVOr(a, b, 1) => {
318+
let v = others.entry(two_expr_key(a, b)).or_insert(vec![]);
319+
if !v.contains(&e) {
320+
v.push(e);
321+
}
322+
}
323+
_ => {}
324+
});
325+
326+
let mut out = vec![];
327+
for (key, value) in others {
328+
if value.len() > 1 {
329+
match value.as_slice() {
330+
[a, b] => out.push((*a, *b)),
331+
other => todo!("{other:?}"),
332+
}
333+
}
334+
}
335+
out
336+
}
337+
338+
/// Sorts the two expressions to generate a unique key
339+
fn two_expr_key(a: ExprRef, b: ExprRef) -> (ExprRef, ExprRef) {
340+
if usize::from(a) <= usize::from(b) {
341+
(a, b)
342+
} else {
343+
(b, a)
344+
}
345+
}

0 commit comments

Comments
 (0)