|
6 | 6 |
|
7 | 7 | \*******************************************************************/
|
8 | 8 |
|
9 |
| -#include "boolbv.h" |
10 |
| - |
11 | 9 | #include <util/arith_tools.h>
|
12 | 10 | #include <util/expr_util.h>
|
13 | 11 | #include <util/invariant.h>
|
14 | 12 | #include <util/simplify_expr.h>
|
| 13 | +#include <util/ssa_expr.h> |
| 14 | + |
| 15 | +#include "boolbv.h" |
15 | 16 |
|
16 | 17 | /// A method to detect equivalence between experts that can contain typecast
|
17 | 18 | static bool expr_eq(const exprt &expr1, const exprt &expr2)
|
@@ -285,10 +286,110 @@ literalt boolbvt::convert_quantifier(const quantifier_exprt &src)
|
285 | 286 |
|
286 | 287 | void boolbvt::finish_eager_conversion_quantifiers()
|
287 | 288 | {
|
288 |
| - if(quantifier_list.empty()) |
289 |
| - return; |
290 |
| - |
291 |
| - // we do not yet have any elaborate post-processing |
292 | 289 | 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 | + } |
294 | 395 | }
|
0 commit comments