@@ -6,12 +6,13 @@ Author: Daniel Kroening, kroening@kroening.com
66
77\*******************************************************************/
88
9- #include " boolbv.h"
10-
119#include < util/arith_tools.h>
1210#include < util/expr_util.h>
1311#include < util/invariant.h>
1412#include < util/simplify_expr.h>
13+ #include < util/ssa_expr.h>
14+
15+ #include " boolbv.h"
1516
1617// / A method to detect equivalence between experts that can contain typecast
1718static bool expr_eq (const exprt &expr1, const exprt &expr2)
@@ -285,10 +286,110 @@ literalt boolbvt::convert_quantifier(const quantifier_exprt &src)
285286
286287void boolbvt::finish_eager_conversion_quantifiers ()
287288{
288- if (quantifier_list.empty ())
289- return ;
290-
291- // we do not yet have any elaborate post-processing
292289 for (const auto &q : quantifier_list)
293- conversion_failed (q.expr );
290+ {
291+ const auto &q_expr = to_quantifier_expr (q.expr );
292+
293+ // we don't yet do nested quantifiers
294+ if (can_cast_expr<quantifier_exprt>(q_expr.where ()))
295+ {
296+ conversion_failed (q.expr );
297+ continue ;
298+ }
299+
300+ // we don't yet handle multiple bound variables
301+ if (q_expr.variables ().size () > 1 )
302+ {
303+ conversion_failed (q.expr );
304+ continue ;
305+ }
306+
307+ // find the context in which any of the bound variables are used
308+ std::unordered_set<irep_idt, irep_id_hash> bound_variables;
309+ for (const auto &v : q_expr.variables ())
310+ bound_variables.insert (v.get_identifier ());
311+
312+ bool required_context = false ;
313+ std::unordered_set<index_exprt, irep_hash> index_contexts;
314+ auto context_finder =
315+ [&bound_variables, &required_context, &index_contexts](const exprt &e) {
316+ if (auto symbol_expr = expr_try_dynamic_cast<symbol_exprt>(e))
317+ {
318+ required_context |=
319+ bound_variables.find (symbol_expr->get_identifier ()) !=
320+ bound_variables.end ();
321+ }
322+ else if (required_context)
323+ {
324+ if (auto index_expr = expr_try_dynamic_cast<index_exprt>(e))
325+ {
326+ index_contexts.insert (*index_expr);
327+ required_context = false ;
328+ }
329+ }
330+ };
331+ q_expr.where ().visit_post (context_finder);
332+ // make sure we found some context for instantiation
333+ if (index_contexts.empty ())
334+ {
335+ conversion_failed (q.expr );
336+ continue ;
337+ }
338+
339+ // match the contexts against expressions that we have cached
340+ std::unordered_set<exprt, irep_hash> instantiation_candidates;
341+ for (const auto &cache_entry : bv_cache)
342+ {
343+ // consider re-organizing the cache to use expression ids at the top level
344+ if (
345+ auto index_expr = expr_try_dynamic_cast<index_exprt>(cache_entry.first ))
346+ {
347+ for (const auto &index_context : index_contexts)
348+ {
349+ if (
350+ auto ssa_context =
351+ expr_try_dynamic_cast<ssa_exprt>(index_context.array ()))
352+ {
353+ if (
354+ auto ssa_array =
355+ expr_try_dynamic_cast<ssa_exprt>(index_expr->array ()))
356+ {
357+ if (
358+ ssa_context->get_l1_object_identifier () ==
359+ ssa_array->get_l1_object_identifier ())
360+ {
361+ instantiation_candidates.insert (index_expr->index ());
362+ break ;
363+ }
364+ }
365+ }
366+ else if (index_expr->array () == index_context.array ())
367+ {
368+ instantiation_candidates.insert (index_expr->index ());
369+ break ;
370+ }
371+ }
372+ }
373+ }
374+
375+ if (instantiation_candidates.empty ())
376+ {
377+ conversion_failed (q.expr );
378+ continue ;
379+ }
380+
381+ exprt::operandst instantiations;
382+ instantiations.reserve (instantiation_candidates.size ());
383+ for (const auto &e : instantiation_candidates)
384+ {
385+ exprt::operandst values{
386+ {typecast_exprt::conditional_cast (e, q_expr.symbol ().type ())}};
387+ instantiations.push_back (q_expr.instantiate (values));
388+ }
389+ exprt result_expr = q_expr.id () == ID_exists ? disjunction (instantiations)
390+ : conjunction (instantiations);
391+ literalt result_lit = convert (result_expr);
392+
393+ prop.l_set_to_true (prop.lequal (q.l , result_lit));
394+ }
294395}
0 commit comments