22// released under BSD 3-Clause License
33// author: Kevin Laeufer <laeufer@cornell.edu>
44
5+ mod backwards;
6+
7+ use crate :: backwards:: backwards_sub;
58use baa:: { BitVecOps , BitVecValue , BitVecValueRef } ;
69use patronus:: expr:: * ;
710use polysub:: { Coef , Term , VarIndex } ;
@@ -153,166 +156,23 @@ fn extract_bit(ctx: &mut Context, e: ExprRef, bit: WidthInt) -> ExprRef {
153156}
154157
155158type DefaultCoef = polysub:: ArrayCoef < 8 > ;
159+ /// Used for building the word-level polynomial
156160type Poly = polysub:: Polynom < DefaultCoef > ;
157161
158162fn expr_to_var ( e : ExprRef ) -> polysub:: VarIndex {
159163 ( usize:: from ( e) as u32 ) . into ( )
160164}
161165
162- /// converts the two expression references and ensures that the smallest var index is returned first
163- #[ inline]
164- fn exprs_to_vars_commutative ( a : ExprRef , b : ExprRef ) -> ( VarIndex , VarIndex ) {
165- let a = expr_to_var ( a) ;
166- let b = expr_to_var ( b) ;
167- if a > b { ( b, a) } else { ( a, b) }
168- }
169-
170166fn var_to_expr ( v : polysub:: VarIndex ) -> ExprRef {
171167 usize:: from ( v) . into ( )
172168}
173169
174- fn backwards_sub (
175- ctx : & Context ,
176- input_vars : & FxHashSet < VarIndex > ,
177- mut todo : Vec < ( VarIndex , ExprRef ) > ,
178- mut spec : Poly ,
179- ) -> Poly {
180- let mut var_roots: Vec < _ > = todo. iter ( ) . map ( |( v, _) | * v) . collect ( ) ;
181- var_roots. sort ( ) ;
182-
183- let m = spec. get_mod ( ) ;
184- let one: DefaultCoef = Coef :: from_i64 ( 1 , m) ;
185- let zero: DefaultCoef = Coef :: from_i64 ( 0 , m) ;
186- let minus_one: DefaultCoef = Coef :: from_i64 ( -1 , m) ;
187- let minus_two: DefaultCoef = Coef :: from_i64 ( -2 , m) ;
188- // first, we count how often expressions are used
189- let roots: Vec < _ > = todo. iter ( ) . map ( |( _, e) | * e) . collect ( ) ;
190- let mut uses = count_expr_uses ( ctx, roots) ;
191- let mut replaced = vec ! [ ] ;
192-
193- let const_true_var = expr_to_var ( ctx. get_true ( ) ) ;
194-
195- while let Some ( ( output_var, gate) ) = todo. pop ( ) {
196- replaced. push ( output_var) ;
197- println ! ( "{output_var} {:?}: {}" , & ctx[ gate] , spec. size( ) ) ;
198-
199- let add_children = match ctx[ gate] . clone ( ) {
200- Expr :: BVOr ( a, b, 1 ) => {
201- // a + b - ab
202- let ( x0, x1) = exprs_to_vars_commutative ( a, b) ;
203- let monoms = [
204- ( one. clone ( ) , vec ! [ x0] . into ( ) ) ,
205- ( one. clone ( ) , vec ! [ x1] . into ( ) ) ,
206- ( minus_one. clone ( ) , vec ! [ x0, x1] . into ( ) ) ,
207- ] ;
208- assert_ne ! ( gate, a) ;
209- assert_ne ! ( gate, b) ;
210- spec. replace_var ( output_var, & monoms) ;
211- true
212- }
213- Expr :: BVXor ( a, b, 1 ) => {
214- // a + b - 2ab
215- let ( x0, x1) = exprs_to_vars_commutative ( a, b) ;
216- let monoms = [
217- ( one. clone ( ) , vec ! [ x0] . into ( ) ) ,
218- ( one. clone ( ) , vec ! [ x1] . into ( ) ) ,
219- ( minus_two. clone ( ) , vec ! [ x0, x1] . into ( ) ) ,
220- ] ;
221- assert_ne ! ( gate, a) ;
222- assert_ne ! ( gate, b) ;
223- spec. replace_var ( output_var, & monoms) ;
224- true
225- }
226- Expr :: BVAnd ( a, b, 1 ) => {
227- // ab
228- let ( x0, x1) = exprs_to_vars_commutative ( a, b) ;
229- let monoms = [ ( one. clone ( ) , vec ! [ x0, x1] . into ( ) ) ] ;
230- assert_ne ! ( gate, a) ;
231- assert_ne ! ( gate, b) ;
232- spec. replace_var ( output_var, & monoms) ;
233- true
234- }
235- Expr :: BVNot ( a, 1 ) => {
236- // 1 - a
237- let x0 = expr_to_var ( a) ;
238- let monoms = [
239- ( one. clone ( ) , vec ! [ ] . into ( ) ) ,
240- ( minus_one. clone ( ) , vec ! [ x0] . into ( ) ) ,
241- ] ;
242- assert_ne ! ( gate, a) ;
243- spec. replace_var ( output_var, & monoms) ;
244- true
245- }
246- Expr :: BVSlice { hi, lo, e } => {
247- assert_eq ! ( hi, lo) ;
248- assert ! (
249- input_vars. contains( & expr_to_var( e) ) ,
250- "Not actually an input: {e:?}"
251- ) ;
252- // a bit slice normally marks an input, thus we should be done!
253- false
254- }
255- Expr :: BVLiteral ( value) => {
256- let value = value. get ( ctx) ;
257- debug_assert_eq ! ( value. width( ) , 1 ) ;
258- if value. is_true ( ) {
259- spec. replace_var ( output_var, & [ ( one. clone ( ) , vec ! [ ] . into ( ) ) ] ) ;
260- } else {
261- spec. replace_var ( output_var, & [ ( zero. clone ( ) , vec ! [ ] . into ( ) ) ] ) ;
262- }
263- false
264- }
265- other => todo ! ( "add support for {other:?}" ) ,
266- } ;
267-
268- if add_children {
269- ctx[ gate] . for_each_child ( |& e| {
270- // reduce the use by one
271- let prev_uses = uses[ e] ;
272- assert ! ( prev_uses > 0 ) ;
273- uses[ e] = prev_uses - 1 ;
274- // did the use count just go down to zero?
275- let var = expr_to_var ( e) ;
276- if prev_uses == 1 && !input_vars. contains ( & var) {
277- todo. push ( ( var, e) ) ;
278- }
279- } ) ;
280- }
281- }
282-
283- println ! ( "Roots: {var_roots:?}" ) ;
284-
285- replaced. sort ( ) ;
286- println ! ( "Replaced variables: {replaced:?}" ) ;
287-
288- // find any expressions where uses are not zero
289- use patronus:: expr:: ExprMap ;
290- let mut still_used: Vec < _ > = uses
291- . iter ( )
292- . filter ( |( _, v) | * * v > 0 )
293- . map ( |( k, _) | expr_to_var ( k) )
294- . collect ( ) ;
295- still_used. sort ( ) ;
296- println ! ( "Still used: {still_used:?}" ) ;
297-
298- let mut remaining_vars: Vec < _ > = spec
299- . sorted_monom_vec ( )
300- . iter ( )
301- . flat_map ( |( _, t) | t. vars ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) )
302- . collect ( ) ;
303- remaining_vars. sort ( ) ;
304- remaining_vars. dedup ( ) ;
305- println ! ( "Remaining vars: {remaining_vars:?}" ) ;
306-
307- spec
308- }
309-
310170fn poly_for_bv_expr ( ctx : & mut Context , e : ExprRef ) -> Poly {
311171 let width = e
312172 . get_bv_type ( ctx)
313173 . expect ( "function only works with bitvector expressions." ) ;
314174 let m = polysub:: Mod :: from_bits ( width) ;
315- polysub :: Polynom :: from_monoms (
175+ Poly :: from_monoms (
316176 m,
317177 ( 0 ..width) . map ( |ii| {
318178 // add an entry for each bit
@@ -332,7 +192,7 @@ fn poly_for_bv_literal(value: BitVecValueRef) -> Poly {
332192 let coef = Coef :: from_big ( & big_value, m) ;
333193 // now we create a polynomial with just this coefficient
334194 let monom = ( coef, vec ! [ ] . into ( ) ) ;
335- polysub :: Polynom :: from_monoms ( m, vec ! [ monom] . into_iter ( ) )
195+ Poly :: from_monoms ( m, vec ! [ monom] . into_iter ( ) )
336196}
337197
338198/// Returns a polynomial representation of the expression + all input expressions if possible.
0 commit comments