1 /*
2  * This file is part of the Yices SMT Solver.
3  * Copyright (C) 2017 SRI International.
4  *
5  * Yices is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Yices is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Yices.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /*
20  * SUPPORT FOR CONVERTING BIT-VECTOR POLYNOMIALS
21  * TO ELEMENTARY EXPRESSIONS.
22  */
23 
24 #include <assert.h>
25 
26 #include "solvers/bv/bvpoly_compiler.h"
27 #include "terms/bv64_constants.h"
28 #include "utils/bit_tricks.h"
29 
30 
31 #define TRACE 0
32 
33 #if TRACE
34 
35 #include <stdio.h>
36 #include <inttypes.h>
37 
38 #include "solvers/bv/bvsolver_printer.h"
39 
40 #endif
41 
42 
43 /*
44  * QUEUES
45  */
46 
47 /*
48  * Initialize to empty queue
49  */
init_bvc_queue(bvc_queue_t * queue)50 static inline void init_bvc_queue(bvc_queue_t *queue) {
51   queue->data = NULL;
52   queue->top = 0;
53   queue->size = 0;
54 }
55 
56 
57 /*
58  * Make the queue larger
59  */
bvc_queue_extend(bvc_queue_t * queue)60 static void bvc_queue_extend(bvc_queue_t *queue) {
61   uint32_t n;
62 
63   n = queue->size;
64   if (n == 0) {
65     // first allocation
66     n = DEF_BVC_QUEUE_SIZE;
67     assert(n > 0 && n <= MAX_BVC_QUEUE_SIZE && queue->data == NULL);
68   } else {
69     n += (n >> 1); // 50% large
70     assert(n > queue->size);
71     if (n > MAX_BVC_QUEUE_SIZE) {
72       out_of_memory();
73     }
74   }
75 
76   queue->data = (thvar_t *) safe_realloc(queue->data, n * sizeof(thvar_t));
77   queue->size = n;
78 }
79 
80 
81 /*
82  * Push x on the queue
83  */
bvc_queue_push(bvc_queue_t * queue,thvar_t x)84 static void bvc_queue_push(bvc_queue_t *queue, thvar_t x) {
85   uint32_t i;
86 
87   i = queue->top;
88   if (i == queue->size) {
89     bvc_queue_extend(queue);
90   }
91   assert(i < queue->size);
92   queue->data[i] = x;
93   queue->top = i + 1;
94 }
95 
96 
97 /*
98  * Empty the queue
99  */
reset_bvc_queue(bvc_queue_t * queue)100 static inline void reset_bvc_queue(bvc_queue_t *queue) {
101   queue->top = 0;
102 }
103 
104 
105 /*
106  * Delete
107  */
delete_bvc_queue(bvc_queue_t * queue)108 static void delete_bvc_queue(bvc_queue_t *queue) {
109   if (queue->data != NULL) {
110     safe_free(queue->data);
111     queue->data = NULL;
112   }
113 }
114 
115 
116 
117 
118 
119 /*
120  * COMPILER
121  */
122 
123 /*
124  * Initialize:
125  * - vtbl = attached variable table
126  * - mtbl = attached merge table
127  */
init_bv_compiler(bvc_t * c,bv_vartable_t * vtbl,mtbl_t * mtbl)128 void init_bv_compiler(bvc_t *c, bv_vartable_t *vtbl, mtbl_t *mtbl) {
129   c->vtbl = vtbl;
130   c->mtbl = mtbl;
131   init_back_hmap(&c->cmap, 0);
132   init_bvc_queue(&c->elemexp);
133 
134   init_bvc_dag(&c->dag, 0);
135   init_bvc_queue(&c->queue);
136   init_int_bvset(&c->in_queue, 0);
137 
138   init_ivector(&c->buffer, 10);
139   init_bvpoly_buffer(&c->pbuffer);
140   init_pp_buffer(&c->pp_buffer, 10);
141 }
142 
143 
144 /*
145  * Delete
146  */
delete_bv_compiler(bvc_t * c)147 void delete_bv_compiler(bvc_t *c) {
148   delete_back_hmap(&c->cmap);
149   delete_bvc_queue(&c->elemexp);
150 
151   delete_bvc_dag(&c->dag);
152   delete_bvc_queue(&c->queue);
153   delete_int_bvset(&c->in_queue);
154 
155   delete_ivector(&c->buffer);
156   delete_bvpoly_buffer(&c->pbuffer);
157   delete_pp_buffer(&c->pp_buffer);
158 }
159 
160 
161 /*
162  * Empty
163  */
reset_bv_compiler(bvc_t * c)164 void reset_bv_compiler(bvc_t *c) {
165   reset_back_hmap(&c->cmap);
166   reset_bvc_queue(&c->elemexp);
167 
168   reset_bvc_dag(&c->dag);
169   reset_bvc_queue(&c->queue);
170   reset_int_bvset(&c->in_queue);
171 
172   ivector_reset(&c->buffer);
173   reset_bvpoly_buffer(&c->pbuffer, 32); // any bitsize would do
174   pp_buffer_reset(&c->pp_buffer);
175 }
176 
177 
178 /*
179  * Push: prepare a backtrack point
180  */
bv_compiler_push(bvc_t * c)181 void bv_compiler_push(bvc_t *c) {
182   back_hmap_push(&c->cmap);
183 }
184 
185 /*
186  * For pop: remove all variables with index >= nv
187  */
bvc_queue_remove_vars(bvc_queue_t * q,uint32_t nv)188 static void bvc_queue_remove_vars(bvc_queue_t *q, uint32_t nv) {
189   uint32_t i, n, j;
190   thvar_t x;
191 
192   j = 0;
193   n = q->top;
194   for (i=0; i<n; i++) {
195     x = q->data[i];
196     if (x < nv) {
197       q->data[j] = x;
198       j ++;
199     }
200   }
201   q->top = j;
202 }
203 
bv_compiler_pop(bvc_t * c,uint32_t nv)204 void bv_compiler_pop(bvc_t *c, uint32_t nv) {
205   back_hmap_pop(&c->cmap);
206   bvc_queue_remove_vars(&c->elemexp, nv);
207 }
208 
209 
210 
211 /*
212  * Set level to n:
213  * - this has the same effect as calling push n times
214  * - we use this function to make sure the compiler's internal
215  *   level is the same as the bv_solver when the compiler i
216  *   allocated.
217  */
bv_compiler_set_level(bvc_t * c,uint32_t n)218 void bv_compiler_set_level(bvc_t *c, uint32_t n) {
219   back_hmap_set_level(&c->cmap, n);
220 }
221 
222 
223 
224 /*
225  * Get the variable mapped to x in cmap
226  * - return -1 if nothing is mapped to x
227  */
bvvar_compiles_to(bvc_t * c,thvar_t x)228 thvar_t bvvar_compiles_to(bvc_t *c, thvar_t x) {
229   back_hmap_elem_t *p;
230   thvar_t y;
231 
232   assert(0 < x && x < c->vtbl->nvars);
233 
234   y = null_thvar;
235   p = back_hmap_find(&c->cmap, x);
236   if (p != NULL) {
237     y = p->val;
238     assert(0 < y && y < c->vtbl->nvars);
239   }
240 
241   return y;
242 }
243 
244 
245 /*
246  * Store the mapping [x --> y] in c->cmap
247  */
bv_compiler_store_map(bvc_t * c,thvar_t x,thvar_t y)248 static void bv_compiler_store_map(bvc_t *c, thvar_t x, thvar_t y) {
249   back_hmap_elem_t *p;
250 
251   assert(0 < x && x < c->vtbl->nvars && 0 < y && y < c->vtbl->nvars && x != y);
252 
253   p = back_hmap_get(&c->cmap, x);
254   assert(p->val == -1);
255   p->val = y;
256 }
257 
258 
259 
260 /*
261  * CONSTRUCTORS FOR ELEMENTARY EXPRESSIONS
262  */
263 
264 /*
265  * Map x to a constant a
266  * - n = number of bits in a
267  */
bv_compiler_map_to_const64(bvc_t * c,thvar_t x,uint64_t a,uint32_t n)268 static void bv_compiler_map_to_const64(bvc_t *c, thvar_t x, uint64_t a, uint32_t n) {
269   thvar_t v;
270 
271   assert(1 <= n && n <= 64 && a == norm64(a, n));
272   v = get_bvconst64(c->vtbl, n, a);
273   bv_compiler_store_map(c, x, v);
274 }
275 
276 
bv_compiler_map_to_const(bvc_t * c,thvar_t x,uint32_t * a,uint32_t n)277 static void bv_compiler_map_to_const(bvc_t *c, thvar_t x, uint32_t *a, uint32_t n) {
278   thvar_t v;
279 
280   assert(n > 64 && bvconst_is_normalized(a, n));
281   v = get_bvconst(c->vtbl, n, a);
282   bv_compiler_store_map(c, x, v);
283 }
284 
285 
286 // variant: constant = 0
bv_compiler_map_to_zero(bvc_t * c,thvar_t x,uint32_t n)287 static void bv_compiler_map_to_zero(bvc_t *c, thvar_t x, uint32_t n) {
288   uint32_t aux[8];
289   uint32_t *a;
290   uint32_t w;
291 
292   assert(n > 64);
293   w = (n+31) >> 5;
294   if (w <= 8) {
295     bvconst_clear(aux, w);
296     bv_compiler_map_to_const(c, x, aux, n);
297   } else {
298     a = bvconst_alloc(w);
299     bvconst_clear(a, w);
300     bv_compiler_map_to_const(c, x, a, n);
301     bvconst_free(a, w);
302   }
303 }
304 
305 
306 /*
307  * In all constructors:
308  * - n = number of bits
309  * - x (and y) = operands
310  */
bv_compiler_mk_bvadd(bvc_t * c,uint32_t n,thvar_t x,thvar_t y)311 static thvar_t bv_compiler_mk_bvadd(bvc_t *c, uint32_t n, thvar_t x, thvar_t y) {
312   thvar_t v;
313   bool new;
314 
315   assert(0 < x && x < c->vtbl->nvars && 0 < y && y < c->vtbl->nvars);
316 
317   // normalize: left operand <= right operand
318   if (x > y) {
319     v = x; x = y; y = v;
320   }
321 
322   v = get_bvadd(c->vtbl, n, x, y, &new);
323   if (new) {
324     bvc_queue_push(&c->elemexp, v);
325   }
326 
327   return v;
328 }
329 
bv_compiler_mk_bvsub(bvc_t * c,uint32_t n,thvar_t x,thvar_t y)330 static thvar_t bv_compiler_mk_bvsub(bvc_t *c, uint32_t n, thvar_t x, thvar_t y) {
331   thvar_t v;
332   bool new;
333 
334   assert(0 < x && x < c->vtbl->nvars && 0 < y && y < c->vtbl->nvars);
335 
336   v = get_bvsub(c->vtbl, n, x, y, &new);
337   if (new) {
338     bvc_queue_push(&c->elemexp, v);
339   }
340 
341   return v;
342 }
343 
bv_compiler_mk_bvmul(bvc_t * c,uint32_t n,thvar_t x,thvar_t y)344 static thvar_t bv_compiler_mk_bvmul(bvc_t *c, uint32_t n, thvar_t x, thvar_t y) {
345   thvar_t v;
346   bool new;
347 
348   assert(0 < x && x < c->vtbl->nvars && 0 < y && y < c->vtbl->nvars);
349 
350   // normalize: left operand <= right operand
351   if (x > y) {
352     v = x; x = y; y = v;
353   }
354 
355   v = get_bvmul(c->vtbl, n, x, y, &new);
356   if (new) {
357     bvc_queue_push(&c->elemexp, v);
358   }
359 
360   return v;
361 }
362 
bv_compiler_mk_bvneg(bvc_t * c,uint32_t n,thvar_t x)363 static thvar_t bv_compiler_mk_bvneg(bvc_t *c, uint32_t n, thvar_t x) {
364   thvar_t v;
365   bool new;
366 
367   assert(0 < x && x < c->vtbl->nvars);
368 
369   v = get_bvneg(c->vtbl, n, x, &new);
370   if (new) {
371     bvc_queue_push(&c->elemexp, v);
372   }
373 
374   return v;
375 }
376 
bv_compiler_mk_zero(bvc_t * c,uint32_t n)377 static thvar_t bv_compiler_mk_zero(bvc_t *c, uint32_t n) {
378   uint32_t aux[8];
379   uint32_t *a;
380   uint32_t w;
381   thvar_t v;
382 
383   assert(1 <= n);
384 
385   if (n <= 64) {
386     v = get_bvconst64(c->vtbl, n, 0);
387   } else {
388     w = (n+31) >> 5;
389     a = aux;
390     if (w > 8) {
391       a = bvconst_alloc(w);
392     }
393     bvconst_clear(a, w);
394     v = get_bvconst(c->vtbl, n, a);
395     if (w > 8) {
396       bvconst_free(a, w);
397     }
398   }
399 
400   bvc_queue_push(&c->elemexp, v);
401 
402   return v;
403 }
404 
bv_compiler_mk_const64(bvc_t * c,uint64_t a,uint32_t n)405 static thvar_t bv_compiler_mk_const64(bvc_t *c, uint64_t a, uint32_t n) {
406   thvar_t v;
407 
408   assert(1 <= n && n <= 64 && a == norm64(a, n));
409   v = get_bvconst64(c->vtbl, n, a);
410   bvc_queue_push(&c->elemexp, v);
411 
412   return v;
413 }
414 
bv_compiler_mk_const(bvc_t * c,uint32_t * a,uint32_t n)415 static thvar_t bv_compiler_mk_const(bvc_t *c, uint32_t *a, uint32_t n) {
416   thvar_t v;
417 
418   assert(n > 64 && bvconst_is_normalized(a, n));
419   v = get_bvconst(c->vtbl, n, a);
420   bvc_queue_push(&c->elemexp, v);
421 
422   return v;
423 }
424 
425 
426 /*
427  * POWER-PRODUCT CONSTRUCTION
428  */
429 
430 /*
431  * Build (bvmul x y) but treat x = null_thvar as 1
432  */
mk_bvmul_aux(bvc_t * c,uint32_t n,thvar_t x,thvar_t y)433 static thvar_t mk_bvmul_aux(bvc_t *c, uint32_t n, thvar_t x, thvar_t y) {
434   return x == null_thvar ? y : bv_compiler_mk_bvmul(c, n, x, y);
435 }
436 
437 /*
438  * Build the variable x := (x_1^d_1 ... x_k^d_k)
439  * - where x_1^d_1 ... x_k^d_k is stored in b
440  * - n = number of bits in x_1 ... x_k
441  * - the total degree d_1 + ... + d_k must be positive
442  */
bv_compiler_mk_power_product(bvc_t * c,uint32_t n,pp_buffer_t * b)443 static thvar_t bv_compiler_mk_power_product(bvc_t *c, uint32_t n, pp_buffer_t *b) {
444   varexp_t *a;
445   ivector_t *v;
446   uint32_t i,  m, d;
447   bool zero_deg;
448   thvar_t x;
449 
450 
451   v = &c->buffer;
452   ivector_reset(v);
453 
454   m = b->len;
455   a = b->prod;
456 
457   do {
458     zero_deg = true;
459     x = null_thvar;
460     /*
461      * In each iteration:
462      *  x = product of all variables x_i's that have odd degree
463      *  (or null_thvar if all variables have even degree)
464      *  d_i := d_i/2
465      */
466     for (i=0; i<m; i++) {
467       d = a[i].exp;
468       if ((d & 1) != 0) {
469         x = mk_bvmul_aux(c, n, x, a[i].var);
470       }
471       d >>= 1;
472       a[i].exp = d;
473       zero_deg = zero_deg & (d == 0);
474     }
475 
476     ivector_push(v, x);
477 
478   } while (! zero_deg);
479 
480 
481   /*
482    * v contains [x_0, ... x_t],
483    * the result is x_0 * x_1^2 * x_2^4 ... * x_t^(2^t)
484    */
485   assert(v->size > 0);
486   i = v->size - 1;
487   x = v->data[i];
488   assert(x != null_thvar);
489   while (i > 0) {
490     i --;
491     x = bv_compiler_mk_bvmul(c, n, x, x);
492     x = mk_bvmul_aux(c, n, v->data[i], x);
493   }
494 
495   return x;
496 }
497 
498 
499 
500 /*
501  * SIMPLIFICATION
502  */
503 
504 /*
505  * Apply the substitution stored in the merge table to p
506  * - store the result in the poly_buffer b
507  */
bv_compiler_simplify_poly64(bvc_t * c,bvpoly64_t * p,bvpoly_buffer_t * b)508 static void bv_compiler_simplify_poly64(bvc_t *c, bvpoly64_t *p,  bvpoly_buffer_t *b) {
509   bv_vartable_t *vtbl;
510   uint32_t i, n;
511   thvar_t x;
512 
513   reset_bvpoly_buffer(b, p->bitsize);
514 
515   vtbl = c->vtbl;
516 
517   n = p->nterms;
518   i = 0;
519   if (p->mono[0].var == const_idx) {
520     bvpoly_buffer_add_const64(b, p->mono[0].coeff);
521     i ++;
522   }
523 
524   while (i < n) {
525     assert(p->mono[i].var != const_idx);
526     x = mtbl_get_root(c->mtbl, p->mono[i].var);
527     //    x = bv_compiler_subst_var(c, p->mono[i].var);
528     if (bvvar_is_const64(vtbl, x)) {
529       bvpoly_buffer_add_const64(b, p->mono[i].coeff * bvvar_val64(vtbl, x));
530     } else {
531       bvpoly_buffer_add_mono64(b, x, p->mono[i].coeff);
532     }
533     i ++;
534   }
535 
536   normalize_bvpoly_buffer(b);
537 }
538 
bv_compiler_simplify_poly(bvc_t * c,bvpoly_t * p,bvpoly_buffer_t * b)539 static void bv_compiler_simplify_poly(bvc_t *c, bvpoly_t *p, bvpoly_buffer_t *b) {
540   bv_vartable_t *vtbl;
541   uint32_t i, n;
542   thvar_t x;
543 
544   reset_bvpoly_buffer(b, p->bitsize);
545 
546   vtbl = c->vtbl;
547 
548   n = p->nterms;
549   i = 0;
550   if (p->mono[0].var == const_idx) {
551     bvpoly_buffer_add_constant(b, p->mono[0].coeff);
552     i ++;
553   }
554 
555   while (i < n) {
556     assert(p->mono[i].var != const_idx);
557     x = mtbl_get_root(c->mtbl, p->mono[i].var);
558     //    x = bv_compiler_subst_var(c, p->mono[i].var);
559     if (bvvar_is_const(vtbl, x)) {
560       bvpoly_buffer_addmul_constant(b, p->mono[i].coeff, bvvar_val(vtbl, x));
561     } else {
562       bvpoly_buffer_add_monomial(b, x, p->mono[i].coeff);
563     }
564     i ++;
565   }
566 
567   normalize_bvpoly_buffer(b);
568 }
569 
570 
571 /*
572  * COMPILATION PHASE 1: STORE VARIABLES TO COMPILE
573  */
574 
575 /*
576  * Check whether x is in cmap
577  */
bvvar_is_compiled(bvc_t * c,thvar_t x)578 static inline bool bvvar_is_compiled(bvc_t *c, thvar_t x) {
579   return back_hmap_find(&c->cmap, x) != NULL;
580 }
581 
582 
583 /*
584  * Check whether x must be added to the queue
585  * - i.e., x is not already compiled and not already in the queue
586  */
bvvar_to_process(bvc_t * c,thvar_t x)587 static bool bvvar_to_process(bvc_t *c, thvar_t x) {
588   return !int_bvset_member(&c->in_queue, x) && !bvvar_is_compiled(c, x);
589 }
590 
591 
592 /*
593  * Add variable x to the internal queue
594  * - also recursively add all the children of x
595  *   so that the children precede x in c->queue
596  */
bv_compiler_push_poly64(bvc_t * c,bvpoly64_t * p)597 static void bv_compiler_push_poly64(bvc_t *c, bvpoly64_t *p) {
598   uint32_t i, n;
599   thvar_t x;
600 
601   n = p->nterms;
602   i = 0;
603   if (p->mono[0].var == const_idx) {
604     i = 1;
605   }
606   while (i < n) {
607     x = mtbl_get_root(c->mtbl, p->mono[i].var);
608     bv_compiler_push_var(c, x);
609     i ++;
610   }
611 }
612 
bv_compiler_push_poly(bvc_t * c,bvpoly_t * p)613 static void bv_compiler_push_poly(bvc_t *c, bvpoly_t *p) {
614   uint32_t i, n;
615   thvar_t x;
616 
617   n = p->nterms;
618   i = 0;
619   if (p->mono[0].var == const_idx) {
620     i = 1;
621   }
622   while (i < n) {
623     x = mtbl_get_root(c->mtbl, p->mono[i].var);
624     bv_compiler_push_var(c, x);
625     i ++;
626   }
627 }
628 
bv_compiler_push_pprod(bvc_t * c,pprod_t * p)629 static void bv_compiler_push_pprod(bvc_t *c, pprod_t *p) {
630   uint32_t i, n;
631   thvar_t x;
632 
633   n = p->len;
634   for (i=0; i<n; i++) {
635     x = mtbl_get_root(c->mtbl, p->prod[i].var);
636     bv_compiler_push_var(c, x);
637   }
638 }
639 
640 
641 /*
642  * Add x and all the variables on which x depends to the queue
643  * - mark x first (to prevent looping if there are  circular dependencies)
644  * - recursively push the children
645  * - then add x to the queue
646  */
bv_compiler_push_var(bvc_t * c,thvar_t x)647 void bv_compiler_push_var(bvc_t *c, thvar_t x) {
648   bv_vartable_t *vtbl;
649 
650   assert(0 < x && x < c->vtbl->nvars);
651 
652   vtbl = c->vtbl;
653 
654   switch (bvvar_tag(vtbl, x)) {
655   case BVTAG_POLY64:
656     if (bvvar_to_process(c, x)) {
657       int_bvset_add(&c->in_queue, x);
658       bv_compiler_push_poly64(c, bvvar_poly64_def(vtbl, x));
659       bvc_queue_push(&c->queue, x);
660     }
661     break;
662 
663   case BVTAG_POLY:
664     if (bvvar_to_process(c, x)) {
665       int_bvset_add(&c->in_queue, x);
666       bv_compiler_push_poly(c, bvvar_poly_def(vtbl, x));
667       bvc_queue_push(&c->queue, x);
668     }
669     break;
670 
671   case BVTAG_PPROD:
672     if (bvvar_to_process(c, x)) {
673       int_bvset_add(&c->in_queue, x);
674       bv_compiler_push_pprod(c, bvvar_pprod_def(vtbl, x));
675       bvc_queue_push(&c->queue, x);
676     }
677     break;
678 
679   default:
680     // skip x
681     break;
682   }
683 }
684 
685 
686 
687 /*
688  * COMPILATION PHASE 2: CONVERT TO THE DAG REPRESENTATION
689  */
690 
691 /*
692  * Convert p to a DAG node
693  * - return the node occurrence
694  * - all variables of p that are not in dag->vsets are mapped to leaf nodes
695  */
bv_compiler_pprod_to_dag(bvc_t * c,pprod_t * p,uint32_t bitsize)696 static node_occ_t bv_compiler_pprod_to_dag(bvc_t *c, pprod_t *p, uint32_t bitsize) {
697   bvc_dag_t *dag;
698   ivector_t *v;
699   uint32_t i, n;
700   thvar_t x;
701   node_occ_t q;
702 
703   dag = &c->dag;
704 
705   v = &c->buffer;
706   ivector_reset(v);
707 
708   n = p->len;
709   for (i=0; i<n; i++) {
710     x = mtbl_get_root(c->mtbl, p->prod[i].var);
711     //    x = bv_compiler_subst_var(c, p->prod[i].var);
712     q = bvc_dag_get_nocc_of_var(dag, x, bitsize);
713     ivector_push(v, q);
714   }
715 
716   return bvc_dag_pprod(dag, p, v->data, bitsize);
717 }
718 
719 
720 /*
721  * Convert polynomial buffer b to DAG:
722  * - b must not be constant
723  */
bv_compiler_pbuffer_to_dag(bvc_t * c,bvpoly_buffer_t * b)724 static node_occ_t bv_compiler_pbuffer_to_dag(bvc_t *c, bvpoly_buffer_t *b) {
725   bvc_dag_t *dag;
726   ivector_t *v;
727   uint32_t i, n, nbits;
728   thvar_t x;
729   node_occ_t q;
730 
731   assert(! bvpoly_buffer_is_constant(b));
732 
733   dag = &c->dag;
734 
735   v = &c->buffer;
736   ivector_reset(v);
737 
738   n = bvpoly_buffer_num_terms(b);
739   nbits = bvpoly_buffer_bitsize(b);
740 
741   i = 0;
742   if (bvpoly_buffer_var(b, 0) == const_idx) {
743     ivector_push(v, const_idx); // need a place-holder in v->data[0]
744     i = 1;
745   }
746   while (i < n) {
747     x = bvpoly_buffer_var(b, i);
748     assert(x != const_idx && mtbl_is_root(c->mtbl, x));
749     q = bvc_dag_get_nocc_of_var(dag, x, nbits);
750     ivector_push(v, q);
751     i++;
752   }
753 
754   return bvc_dag_poly_buffer(dag, b, v->data);
755 }
756 
757 
758 
759 /*
760  * Build a DAG node for x and store the mapping [x --> node]
761  * - x must be a polynomial or a power product
762  */
bv_compiler_map_var_to_dag(bvc_t * c,thvar_t x)763 static void bv_compiler_map_var_to_dag(bvc_t *c, thvar_t x) {
764   bv_vartable_t *vtbl;
765   bvpoly_buffer_t *b;
766   node_occ_t q;
767   uint64_t a;
768 
769   assert(0 < x && x < c->vtbl->nvars && int_bvset_member(&c->in_queue, x));
770 
771   q = -1; // Stop GCC warning
772 
773   vtbl = c->vtbl;
774 
775   switch (bvvar_tag(vtbl, x)) {
776   case BVTAG_POLY64:
777     b = &c->pbuffer;
778     bv_compiler_simplify_poly64(c, bvvar_poly64_def(vtbl, x), b);
779     if (bvpoly_buffer_is_constant(b)) {
780       a = 0;
781       if (!bvpoly_buffer_is_zero(b)) {
782         a = bvpoly_buffer_coeff64(b, 0);
783       }
784       bv_compiler_map_to_const64(c, x, a, b->bitsize);
785       return;
786     }
787     q = bv_compiler_pbuffer_to_dag(c, b);
788     break;
789 
790   case BVTAG_POLY:
791     b = &c->pbuffer;
792     bv_compiler_simplify_poly(c, bvvar_poly_def(vtbl, x), b);
793     if (bvpoly_buffer_is_constant(b)) {
794       if (bvpoly_buffer_is_zero(b)) {
795         bv_compiler_map_to_zero(c, x, b->bitsize);
796       } else {
797         bv_compiler_map_to_const(c, x, bvpoly_buffer_coeff(b, 0), b->bitsize);
798       }
799       return;
800     }
801     q = bv_compiler_pbuffer_to_dag(c, b);
802     break;
803 
804   case BVTAG_PPROD:
805     q = bv_compiler_pprod_to_dag(c, bvvar_pprod_def(vtbl, x), bvvar_bitsize(vtbl, x));
806     break;
807 
808   default:
809     assert(false);
810     break;
811   }
812 
813   bvc_dag_map_var(&c->dag, x, q);
814   int_bvset_remove(&c->in_queue, x);
815 }
816 
817 
818 
819 /*
820  * Simplify the DAG nodes using elementary expression x
821  */
822 
823 // case 1: x is (bvadd y z) where y != z and both y and z occur in the dag
bv_compiler_simplify_dag_bvadd(bvc_t * c,thvar_t x,thvar_t y,thvar_t z)824 static void bv_compiler_simplify_dag_bvadd(bvc_t *c, thvar_t x, thvar_t y, thvar_t z) {
825   bvc_dag_t *dag;
826   node_occ_t ny, nz, nx;
827   uint32_t nbits;
828 
829   dag = &c->dag;
830   ny = bvc_dag_nocc_of_var(dag, y);
831   nz = bvc_dag_nocc_of_var(dag, z);
832   if (bvc_dag_check_reduce_sum(dag, ny, nz)) {
833     nbits = bvvar_bitsize(c->vtbl, x);
834     assert(bvvar_bitsize(c->vtbl, y) == nbits &&
835            bvvar_bitsize(c->vtbl, z) == nbits);
836 
837     nx = bvc_dag_leaf(dag, x, nbits);
838     bvc_dag_reduce_sum(dag, nx, ny, nz);
839   }
840 }
841 
842 // case 2: x is (bvsub y z) where y != z and both y and z occur in the dag
bv_compiler_simplify_dag_bvsub(bvc_t * c,thvar_t x,thvar_t y,thvar_t z)843 static void bv_compiler_simplify_dag_bvsub(bvc_t *c, thvar_t x, thvar_t y, thvar_t z) {
844   bvc_dag_t *dag;
845   node_occ_t ny, nz, nx;
846   uint32_t nbits;
847 
848   dag = &c->dag;
849   ny = bvc_dag_nocc_of_var(dag, y);
850   nz = negate_occ(bvc_dag_nocc_of_var(dag, z));
851   if (bvc_dag_check_reduce_sum(dag, ny, nz)) {
852     nbits = bvvar_bitsize(c->vtbl, x);
853     assert(bvvar_bitsize(c->vtbl, y) == nbits &&
854            bvvar_bitsize(c->vtbl, z) == nbits);
855 
856     nx = bvc_dag_leaf(dag, x, nbits);
857     bvc_dag_reduce_sum(dag, nx, ny, nz);
858   }
859 }
860 
861 // case 3: x is (bvmul y z) where y and z occur in the dag
bv_compiler_simplify_dag_bvmul(bvc_t * c,thvar_t x,thvar_t y,thvar_t z)862 static void bv_compiler_simplify_dag_bvmul(bvc_t *c, thvar_t x, thvar_t y, thvar_t z) {
863   bvc_dag_t *dag;
864   node_occ_t ny, nz, nx;
865   uint32_t nbits;
866 
867   dag = &c->dag;
868   ny = bvc_dag_nocc_of_var(dag, y);
869   nz = bvc_dag_nocc_of_var(dag, z);
870   if (bvc_dag_check_reduce_prod(dag, ny, nz)) {
871     nbits = bvvar_bitsize(c->vtbl, x);
872     assert(bvvar_bitsize(c->vtbl, y) == nbits &&
873            bvvar_bitsize(c->vtbl, z) == nbits);
874 
875     nx = bvc_dag_leaf(dag, x, nbits);
876     bvc_dag_reduce_prod(dag, nx, ny, nz);
877   }
878 }
879 
880 
881 
bv_compiler_simplify_dag(bvc_t * c,thvar_t x)882 static void bv_compiler_simplify_dag(bvc_t *c, thvar_t x) {
883   bv_vartable_t *vtbl;
884   bvc_dag_t *dag;
885   thvar_t *aux;
886   thvar_t y, z;
887 
888   dag = &c->dag;
889   vtbl = c->vtbl;
890   switch (bvvar_tag(vtbl, x)) {
891   case BVTAG_ADD:
892     aux = bvvar_binop(vtbl, x);
893     y = mtbl_get_root(c->mtbl, aux[0]);
894     z = mtbl_get_root(c->mtbl, aux[1]);
895     if (y != z && bvc_dag_var_is_present(dag, y) && bvc_dag_var_is_present(dag, z)) {
896       bv_compiler_simplify_dag_bvadd(c, x, y, z);
897     }
898     break;
899 
900   case BVTAG_SUB:
901     aux = bvvar_binop(vtbl, x);
902     y = mtbl_get_root(c->mtbl, aux[0]);
903     z = mtbl_get_root(c->mtbl, aux[1]);
904     if (y != z && bvc_dag_var_is_present(dag, y) && bvc_dag_var_is_present(dag, z)) {
905       bv_compiler_simplify_dag_bvsub(c, x, y, z);
906     }
907     break;
908 
909   case BVTAG_MUL:
910     aux = bvvar_binop(vtbl, x);
911     y = mtbl_get_root(c->mtbl, aux[0]);
912     z = mtbl_get_root(c->mtbl, aux[1]);
913     if (bvc_dag_var_is_present(dag, y) && bvc_dag_var_is_present(dag, z)) {
914       bv_compiler_simplify_dag_bvmul(c, x, y, z);
915     }
916     break;
917 
918   default:
919     break;
920   }
921 }
922 
923 
924 
925 /*
926  * PHASE 3: CONVERT NODES TO ELEMENTARY EXPRESSIONS
927  */
928 
929 /*
930  * Compilation of an elementary node i
931  */
932 // case 1: i is [offset a0 n]
bvc_process_offset(bvc_t * c,bvnode_t i,bvc_offset_t * d)933 static void bvc_process_offset(bvc_t *c, bvnode_t i, bvc_offset_t *d) {
934   bv_vartable_t *vtbl;
935   uint32_t nbits;
936   thvar_t x, y, z;
937 
938   vtbl = c->vtbl;
939   nbits = d->header.bitsize;
940   if (nbits <= 64) {
941     y = get_bvconst64(vtbl, nbits, d->constant.c);
942   } else {
943     y = get_bvconst(vtbl, nbits, d->constant.w);
944   }
945   z = bvc_dag_get_var_of_leaf(&c->dag, d->nocc);
946 
947   if (sign_of_occ(d->nocc) == 0) {
948     // i is compiled to [bvadd y z]
949     x = bv_compiler_mk_bvadd(c, nbits, y, z);
950   } else {
951     // i is compiled to [bvsub y z];
952     x = bv_compiler_mk_bvsub(c, nbits, y, z);
953   }
954   bvc_dag_convert_to_leaf(&c->dag, i, x);
955 }
956 
957 // case 2: i is [mono a0 n]
bvc_process_monomial(bvc_t * c,bvnode_t i,bvc_mono_t * d)958 static void bvc_process_monomial(bvc_t *c, bvnode_t i, bvc_mono_t *d) {
959   bv_vartable_t *vtbl;
960   uint32_t nbits;
961   thvar_t x, y, z;
962 
963   vtbl = c->vtbl;
964   nbits = d->header.bitsize;
965   if (nbits <= 64) {
966     y = get_bvconst64(vtbl, nbits, d->coeff.c);
967   } else {
968     y = get_bvconst(vtbl, nbits, d->coeff.w);
969   }
970   assert(sign_of_occ(d->nocc) == 0);
971   z = bvc_dag_get_var_of_leaf(&c->dag, d->nocc);
972 
973   // i is compiled to [bvmul y z]
974   x = bv_compiler_mk_bvmul(c, nbits, y, z);
975   bvc_dag_convert_to_leaf(&c->dag, i, x);
976 }
977 
978 // case 3: i is [prod n1 n2] or [prod n1^2]
bvc_process_elem_prod(bvc_t * c,bvnode_t i,bvc_prod_t * d)979 static void bvc_process_elem_prod(bvc_t *c, bvnode_t i, bvc_prod_t *d) {
980   uint32_t nbits;
981   node_occ_t nx, ny, nz;
982   thvar_t x, y, z;
983 
984   assert((d->len == 1 && d->prod[0].exp == 2) ||
985          (d->len == 2 && d->prod[0].exp == 1 && d->prod[1].exp == 1));
986 
987   nbits = d->header.bitsize;
988 
989   ny = d->prod[0].var;
990   assert(sign_of_occ(ny) == 0);
991   y = bvc_dag_get_var_of_leaf(&c->dag, ny);
992   nz = ny;
993   z = y;
994   if (d->len == 2) {
995     nz = d->prod[1].var;
996     assert(sign_of_occ(nz) == 0);
997     z = bvc_dag_get_var_of_leaf(&c->dag, nz);
998   }
999 
1000   // i is compiled to [bvmul y z]
1001   x = bv_compiler_mk_bvmul(c, nbits, y, z);
1002   bvc_dag_convert_to_leaf(&c->dag, i, x);
1003 
1004   // now replace (ny * nz) by nx everywhere
1005   nx = bvp(i);
1006   bvc_dag_reduce_prod(&c->dag, nx, ny, nz);
1007 }
1008 
1009 // case 4: i is [sum n1 n2]
bvc_process_elem_sum(bvc_t * c,bvnode_t i,bvc_sum_t * d)1010 static void bvc_process_elem_sum(bvc_t *c, bvnode_t i, bvc_sum_t *d) {
1011   uint32_t nbits;
1012   node_occ_t nx, ny, nz;
1013   thvar_t x, y, z;
1014 
1015   assert(d->len == 2);
1016 
1017   nbits = d->header.bitsize;
1018   ny = d->sum[0];
1019   nz = d->sum[1];
1020   y = bvc_dag_get_var_of_leaf(&c->dag, ny);
1021   z = bvc_dag_get_var_of_leaf(&c->dag, nz);
1022 
1023   if (sign_of_occ(ny) == 0) {
1024     if (sign_of_occ(nz) == 0) {
1025       // i is compiled to [bvadd y z]
1026       x = bv_compiler_mk_bvadd(c, nbits, y, z);
1027     } else {
1028       // i is compiled to [bvsub y z]
1029       x = bv_compiler_mk_bvsub(c, nbits, y, z);
1030     }
1031   } else {
1032     if (sign_of_occ(nz) == 0) {
1033       // i is compiled to [bvsub z y]
1034       x = bv_compiler_mk_bvsub(c, nbits, z, y);
1035     } else {
1036       // i is compiled to [bnveg [bvadd y z]]?
1037       x = bv_compiler_mk_bvadd(c, nbits, y, z);
1038       x = bv_compiler_mk_bvneg(c, nbits, x);
1039     }
1040   }
1041 
1042   // replace ny nz by nx everywhere
1043   bvc_dag_convert_to_leaf(&c->dag, i, x);
1044   nx = bvp(i);
1045   bvc_dag_reduce_sum(&c->dag, nx, ny, nz);
1046 }
1047 
1048 // case 5: i is zero
bvc_process_zero(bvc_t * c,bvnode_t i,bvc_zero_t * d)1049 static void bvc_process_zero(bvc_t *c, bvnode_t i, bvc_zero_t *d) {
1050   uint32_t nbits;
1051   thvar_t x;
1052 
1053   nbits = d->header.bitsize;
1054   x = bv_compiler_mk_zero(c, nbits);
1055   bvc_dag_convert_to_leaf(&c->dag, i, x);
1056 }
1057 
1058 
1059 // case 6: i is a constant node
bvc_process_constant(bvc_t * c,bvnode_t i,bvc_constant_t * d)1060 static void bvc_process_constant(bvc_t *c, bvnode_t i, bvc_constant_t *d) {
1061   uint32_t nbits;
1062   thvar_t x;
1063 
1064   nbits = d->header.bitsize;
1065   if (nbits <= 64) {
1066     x = bv_compiler_mk_const64(c, d->value.c, nbits);
1067   } else {
1068     x = bv_compiler_mk_const(c, d->value.w, nbits);
1069   }
1070   bvc_dag_convert_to_leaf(&c->dag, i, x);
1071 }
1072 
1073 
bvc_process_elem_node(bvc_t * c,bvnode_t i)1074 static void bvc_process_elem_node(bvc_t *c, bvnode_t i) {
1075   bvc_dag_t *dag;
1076 
1077   dag = &c->dag;
1078   switch (bvc_dag_node_type(dag, i)) {
1079   case BVC_ZERO:
1080     bvc_process_zero(c, i, bvc_dag_node_zero(dag, i));
1081     break;
1082 
1083   case BVC_CONSTANT:
1084     bvc_process_constant(c, i, bvc_dag_node_constant(dag, i));
1085     break;
1086 
1087   case BVC_OFFSET:
1088     bvc_process_offset(c, i, bvc_dag_node_offset(dag, i));
1089     break;
1090 
1091   case BVC_MONO:
1092     bvc_process_monomial(c, i, bvc_dag_node_mono(dag, i));
1093     break;
1094 
1095   case BVC_PROD:
1096     bvc_process_elem_prod(c, i, bvc_dag_node_prod(dag, i));
1097     break;
1098 
1099   case BVC_SUM:
1100     bvc_process_elem_sum(c, i, bvc_dag_node_sum(dag, i));
1101     break;
1102 
1103   case BVC_LEAF:
1104   case BVC_ALIAS:
1105     assert(false);
1106     break;
1107   }
1108 }
1109 
1110 
1111 
1112 /*
1113  * SIMPLE NODES
1114  */
1115 
1116 /*
1117  * Check whether product or sum p is simple:
1118  * - return true if all the nodes occurring in p are leaves
1119  *   and p contains at most one shared leaf
1120  * - we take the degree into account: if p contains product x^k
1121  *   with k>1 and x is shared then that's more than one shared occurrence
1122  */
bvc_prod_is_simple(bvc_dag_t * dag,bvc_prod_t * p)1123 static bool bvc_prod_is_simple(bvc_dag_t *dag, bvc_prod_t *p) {
1124   uint32_t i, n, n_shared;
1125   node_occ_t nx;
1126 
1127   n_shared = 0;
1128   n = p->len;
1129   for (i=0; i<n; i++) {
1130     nx = p->prod[i].var;
1131     if (!bvc_dag_occ_is_leaf(dag, nx)) {
1132       return false;
1133     }
1134     if (bvc_dag_occ_is_shared(dag, nx)) {
1135       //      n_shared ++;
1136       n_shared += p->prod[i].exp;
1137       if (n_shared > 1) return false;
1138     }
1139   }
1140 
1141   assert(n_shared <= 1);
1142 
1143   return true;
1144 }
1145 
bvc_sum_is_simple(bvc_dag_t * dag,bvc_sum_t * p)1146 static bool bvc_sum_is_simple(bvc_dag_t *dag, bvc_sum_t *p) {
1147   uint32_t i, n, n_shared;
1148   node_occ_t nx;
1149 
1150   n_shared = 0;
1151   n = p->len;
1152   for (i=0; i<n; i++) {
1153     nx = p->sum[i];
1154     if (!bvc_dag_occ_is_leaf(dag, nx)) {
1155       return false;
1156     }
1157     if (bvc_dag_occ_is_shared(dag, nx)) {
1158       n_shared ++;
1159       if (n_shared > 1) return false;
1160     }
1161   }
1162 
1163   assert(n_shared <= 1);
1164 
1165   return true;
1166 }
1167 
1168 
1169 /*
1170  * Compilation of a simple/non-elementary node i
1171  */
bvc_process_simple_prod(bvc_t * c,bvnode_t i,bvc_prod_t * p)1172 static void bvc_process_simple_prod(bvc_t *c, bvnode_t i, bvc_prod_t *p) {
1173   pp_buffer_t *pp;
1174   uint32_t j, m, nbits;
1175   thvar_t x;
1176 
1177   assert(p->len >= 1);
1178 
1179   pp = &c->pp_buffer;
1180   pp_buffer_reset(pp);
1181 
1182   /*
1183    * p is [n1^d1 ... n_m^d_m]
1184    * find x_i := variable of leaf node n_i
1185    * then build x = [x1^d1 ... x_m^d_m]
1186    */
1187   nbits = p->header.bitsize;
1188   m = p->len;
1189   for (j=0; j<m; j++) {
1190     assert(sign_of_occ(p->prod[j].var) == 0);
1191     x = bvc_dag_get_var_of_leaf(&c->dag, p->prod[j].var);
1192     pp_buffer_push_varexp(pp, x, p->prod[j].exp);
1193   }
1194 
1195   x = bv_compiler_mk_power_product(c, nbits, pp);
1196 
1197   // replace i by [leaf x] in DAG
1198   bvc_dag_convert_to_leaf(&c->dag, i, x);
1199 }
1200 
bvc_process_simple_sum(bvc_t * c,bvnode_t i,bvc_sum_t * p)1201 static void bvc_process_simple_sum(bvc_t *c, bvnode_t i, bvc_sum_t *p) {
1202   uint32_t j, m, nbits;
1203   node_occ_t n;
1204   thvar_t x, y;
1205   bool all_neg;
1206 
1207   assert(p->len >= 3);
1208 
1209   nbits = p->header.bitsize;
1210   m = p->len;
1211   n = p->sum[0];
1212   x = bvc_dag_get_var_of_leaf(&c->dag, n);
1213   all_neg = (sign_of_occ(n) != 0);
1214 
1215   /*
1216    * Invariant:
1217    * - all_neg means that all node occurrences
1218    *   in 0 ... j-1 have negative sign.
1219    * - if all_neg is true, then x is the opposite
1220    *   if (sum n0 ... n_{j-1})
1221    *   otherwise, x is (sum n0 ... n_{j-1}
1222    */
1223   for (j=1; j<m; j++) {
1224     n = p->sum[j];
1225     y = bvc_dag_get_var_of_leaf(&c->dag, n);
1226     if (all_neg) {
1227       if (sign_of_occ(n) == 0) {
1228         x = bv_compiler_mk_bvsub(c, nbits, y, x);
1229         all_neg = false;
1230       } else {
1231         x = bv_compiler_mk_bvadd(c, nbits, x, y);
1232       }
1233     } else {
1234       if (sign_of_occ(n) == 0) {
1235         x = bv_compiler_mk_bvadd(c, nbits, x, y);
1236       } else {
1237         x = bv_compiler_mk_bvsub(c, nbits, x, y);
1238       }
1239     }
1240   }
1241 
1242   if (all_neg) {
1243     x = bv_compiler_mk_bvneg(c, nbits, x);
1244   }
1245 
1246   // replace i by [leaf x] in DAG
1247   bvc_dag_convert_to_leaf(&c->dag, i, x);
1248 }
1249 
1250 
1251 /*
1252  * Process node i:
1253  * - if it's simple, node i is compiled and moved to the list of leaves
1254  * - otherwise, node i is moved to the auxiliary list (in c->dag)
1255  */
bvc_process_node_if_simple(bvc_t * c,bvnode_t i)1256 static void bvc_process_node_if_simple(bvc_t *c, bvnode_t i) {
1257   bvc_dag_t *dag;
1258   bvc_prod_t *p;
1259   bvc_sum_t *s;
1260 
1261   dag = &c->dag;
1262   switch (bvc_dag_node_type(dag, i)) {
1263   case BVC_OFFSET:
1264   case BVC_MONO:
1265     break; // skip it
1266 
1267   case BVC_PROD:
1268     p = bvc_dag_node_prod(dag, i);
1269     if (bvc_prod_is_simple(dag, p)) {
1270       bvc_process_simple_prod(c, i, p);
1271       return;
1272     }
1273     break;
1274 
1275   case BVC_SUM:
1276     s = bvc_dag_node_sum(dag, i);
1277     if (bvc_sum_is_simple(dag, s)) {
1278       bvc_process_simple_sum(c, i, s);
1279       return;
1280     }
1281     break;
1282 
1283   case BVC_LEAF:
1284   case BVC_ALIAS:
1285   case BVC_ZERO:
1286   case BVC_CONSTANT:
1287     assert(false);
1288     break;
1289   }
1290 
1291   /*
1292    * i not touched: remove it from the complex-node list
1293    */
1294   bvc_move_node_to_aux_list(dag, i);
1295 }
1296 
1297 
1298 
1299 /*
1300  * COMPILATION
1301  */
1302 
1303 /*
1304  * Convert all elementary nodes
1305  */
bv_compiler_convert_elem_nodes(bvc_t * c)1306 static void bv_compiler_convert_elem_nodes(bvc_t *c) {
1307   bvnode_t j;
1308 
1309   /*
1310    * Note: bvc_process_elem_node removes j from the elementary node list
1311    * so we always get the first element of the leaf list until it's empty
1312    */
1313   for (;;) {
1314     j = bvc_first_elem_node(&c->dag);
1315     if (j < 0) break;
1316     bvc_process_elem_node(c, j);
1317 
1318 #if TRACE
1319     printf("\n=== After compiling node n%"PRId32" =====\n", j);
1320     print_bvc_dag(stdout, &c->dag);
1321     fflush(stdout);
1322 #endif
1323   }
1324 }
1325 
1326 
1327 /*
1328  * Convert all simple nodes
1329  */
bv_compiler_convert_simple_nodes(bvc_t * c)1330 static void bv_compiler_convert_simple_nodes(bvc_t *c) {
1331   bvnode_t j;
1332 
1333   for (;;) {
1334     j = bvc_first_complex_node(&c->dag);
1335     if (j < 0) break;
1336     bvc_process_node_if_simple(c, j);
1337 
1338 #if TRACE
1339     printf("\n=== After compiling node n%"PRId32" =====\n", j);
1340     print_bvc_dag(stdout, &c->dag);
1341     fflush(stdout);
1342 #endif
1343 
1344   }
1345   // move back all aux nodes to the complex list
1346   bvc_move_aux_to_complex_list(&c->dag);
1347 }
1348 
1349 
1350 /*
1351  * Auxiliary function: create (bvneg x) if it doesn't exist
1352  * already.
1353  * TODO: check for (bvneg (bvneg z)) and other simplifications?
1354  */
bv_compiler_get_bvneg(bvc_t * c,thvar_t x)1355 static thvar_t bv_compiler_get_bvneg(bvc_t *c, thvar_t x) {
1356   thvar_t y;
1357   uint32_t nbits;
1358 
1359   assert(0 < x && x < c->vtbl->nvars);
1360   y = find_bvneg(c->vtbl, x);
1361   if (y < 0) {
1362     nbits = bvvar_bitsize(c->vtbl, x);
1363     y = bv_compiler_mk_bvneg(c, nbits, x);
1364   }
1365 
1366   return y;
1367 }
1368 
1369 
1370 /*
1371  * Get the variable y that x is compiled to
1372  * - store the mapping [x --> y] in the cmap
1373  */
bv_compiler_store_mapping(bvc_t * c,thvar_t x)1374 static void bv_compiler_store_mapping(bvc_t *c, thvar_t x) {
1375   back_hmap_elem_t *p;
1376   node_occ_t r;
1377   thvar_t y;
1378   uint32_t sign;
1379 
1380   assert(0 < x && x < c->vtbl->nvars);
1381 
1382   p = back_hmap_get(&c->cmap, x);
1383   if (p->val >= 0) {
1384     // x is already compiled (to a constant)
1385     assert(p->val != x);
1386     return;
1387   }
1388 
1389   r  = bvc_dag_nocc_of_var(&c->dag, x); // node occurrence mapped to x
1390   if (bvc_dag_nocc_has_flipped(&c->dag, r)) {
1391     r = negate_occ(r);
1392  }
1393 
1394   y = bvc_dag_get_nocc_compilation(&c->dag, r); // r is compiled to y
1395   assert(y >= 0);
1396 
1397   /*
1398    * y is a pair (variable + sign)
1399    * if the sign is negative, x is mapped to (bvneg variable)
1400    * if the sign is positive, x is mapped to variable
1401    */
1402   sign = (y & 1);
1403   y >>= 1;
1404   assert(bvvar_bitsize(c->vtbl, x) == bvvar_bitsize(c->vtbl, y));
1405   if (sign != 0) {
1406     y = bv_compiler_get_bvneg(c, y);
1407   }
1408   assert(0 < y && y < c->vtbl->nvars && x != y);
1409   p->val = y;
1410 }
1411 
1412 
bv_compiler_process_queue(bvc_t * c)1413 void bv_compiler_process_queue(bvc_t *c) {
1414   uint32_t i, n;
1415 
1416   //  printf("\n=== bv compiler: process-queue: %"PRIu32" variables ===\n", c->vtbl->nvars);
1417   //  printf("Initial compile map\n");
1418   //  show_cmap(c);
1419 
1420   n = c->queue.top;
1421   for (i=0; i<n; i++) {
1422     bv_compiler_map_var_to_dag(c, c->queue.data[i]);
1423   }
1424 
1425 #if TRACE
1426   printf("\n==== INIITIAL DAG ====\n");
1427   print_bvc_dag(stdout, &c->dag);
1428 #endif
1429 
1430   // try to simplify the DAG nodes using existing elementary expressions
1431   n = c->elemexp.top;
1432   for (i=0; i<n; i++) {
1433     bv_compiler_simplify_dag(c, c->elemexp.data[i]);;
1434   }
1435 
1436   // compile the rest until the complex-node list is empty
1437   for (;;) {
1438     bv_compiler_convert_elem_nodes(c);
1439     bv_compiler_convert_simple_nodes(c);
1440     bv_compiler_convert_elem_nodes(c);
1441 
1442     assert(bvc_first_elem_node(&c->dag) < 0);
1443     if (bvc_first_complex_node(&c->dag) < 0) break;
1444 
1445 #if TRACE
1446     printf("\n==== FORCING ELEM NODES ====\n");
1447     print_bvc_dag(stdout, &c->dag);
1448     fflush(stdout);
1449 #endif
1450 
1451     bvc_dag_force_elem_node(&c->dag);
1452 
1453 #if TRACE
1454     printf("\n==== AFTER FORCING ====\n");
1455     print_bvc_dag(stdout, &c->dag);
1456     fflush(stdout);
1457 #endif
1458 
1459   }
1460 
1461 
1462   /*
1463    * Collect the compilation results
1464    */
1465   n = c->queue.top;
1466   for (i=0; i<n; i++) {
1467     bv_compiler_store_mapping(c, c->queue.data[i]);
1468   }
1469 
1470 
1471   /*
1472    * Cleanup
1473    */
1474   reset_bvc_queue(&c->queue);
1475   reset_bvc_dag(&c->dag);
1476   reset_int_bvset(&c->in_queue);
1477 
1478   //  printf("\n=== done: process-queue: %"PRIu32" variables ===\n", c->vtbl->nvars);
1479   //  printf("Final compile map\n");
1480   //  show_cmap(c);
1481 }
1482