@@ -133,9 +133,15 @@ void goto_symext::symex_assume(statet &state, const exprt &cond)
133
133
else
134
134
state.guard .add (simplified_cond);
135
135
136
- if (state.atomic_section_id !=0 &&
137
- state.guard .is_false ())
136
+ if (state.atomic_section_id != 0 && state.guard .is_false ())
138
137
symex_atomic_end (state);
138
+
139
+ if (!simplified_cond.is_false ())
140
+ {
141
+ // try to update the value sets using information contained in the guard
142
+ try_filter_value_sets (
143
+ state, simplified_cond, &state.value_set , nullptr , ns);
144
+ }
139
145
}
140
146
141
147
void goto_symext::rewrite_quantifiers (exprt &expr, statet &state)
@@ -519,3 +525,115 @@ void goto_symext::symex_step(
519
525
UNREACHABLE;
520
526
}
521
527
}
528
+
529
+ // / Collect all sub-expressions of an expression that are pointer-typed symbols
530
+ // / \param expr: The expression to examine
531
+ // / \param [out] output: The set to put the results into
532
+ static void
533
+ collect_pointer_typed_symbols (const exprt &expr, std::set<symbol_exprt> &output)
534
+ {
535
+ const symbol_exprt *symbol_expr = expr_try_dynamic_cast<symbol_exprt>(expr);
536
+ if (symbol_expr && can_cast_type<pointer_typet>(symbol_expr->type ()))
537
+ {
538
+ output.insert (*symbol_expr);
539
+ }
540
+
541
+ for (const exprt &op : expr.operands ())
542
+ {
543
+ collect_pointer_typed_symbols (op, output);
544
+ }
545
+ }
546
+
547
+ void goto_symext::try_filter_value_sets (
548
+ goto_symex_statet &state,
549
+ exprt condition,
550
+ value_sett *value_set_for_true_case,
551
+ value_sett *value_set_for_false_case,
552
+ const namespacet &ns)
553
+ {
554
+ condition = state.rename <goto_symex_statet::L1>(std::move (condition), ns);
555
+
556
+ std::set<symbol_exprt> pointer_typed_symbols{};
557
+ collect_pointer_typed_symbols (condition, pointer_typed_symbols);
558
+
559
+ if (pointer_typed_symbols.size () == 1 )
560
+ {
561
+ const symbol_exprt &symbol_expr = *pointer_typed_symbols.begin ();
562
+ const pointer_typet &symbol_type = to_pointer_type (symbol_expr.type ());
563
+
564
+ // If symbol_expr has already been L2-renamed then we need to strip it back
565
+ // to L1-renaming for the purposes of getting its value set
566
+ const symbol_exprt symbol_expr_l1 =
567
+ is_ssa_expr (symbol_expr) ? to_ssa_expr (symbol_expr).get_l1_object ()
568
+ : symbol_expr;
569
+ value_setst::valuest possible_values;
570
+ state.value_set .get_value_set (symbol_expr_l1, possible_values, ns);
571
+
572
+ // Try evaluating the condition with symbol_expr pointing to each one of
573
+ // its possible values in turn. If that leads to a true from o1 then we can
574
+ // delete that o1 from the value set that will be used if the condition is
575
+ // false, and vice versa.
576
+ for (const auto &possible_value : possible_values)
577
+ {
578
+ if (!can_cast_expr<object_descriptor_exprt>(possible_value))
579
+ {
580
+ continue ;
581
+ }
582
+
583
+ object_descriptor_exprt o = to_object_descriptor_expr (possible_value);
584
+
585
+ const exprt &root_object = o.root_object ();
586
+ const exprt &object = o.object ();
587
+ exprt value_for_symbol_expr;
588
+
589
+ if (root_object.id () == ID_null_object)
590
+ {
591
+ value_for_symbol_expr = null_pointer_exprt{symbol_type};
592
+ }
593
+ else if (root_object.id () == ID_integer_address)
594
+ {
595
+ continue ;
596
+ }
597
+ else
598
+ {
599
+ // We should do something like
600
+ // value_set_dereference::dereference_type_compare, which deals with
601
+ // arrays having types containing void
602
+ if (o.offset ().is_zero () && object.type () == symbol_type.subtype ())
603
+ {
604
+ value_for_symbol_expr = address_of_exprt (object);
605
+ }
606
+ else
607
+ {
608
+ continue ;
609
+ }
610
+ }
611
+
612
+ exprt modified_condition (condition);
613
+
614
+ replace_symbolt replace_symbol{};
615
+ replace_symbol.insert (symbol_expr, value_for_symbol_expr);
616
+ replace_symbol (modified_condition);
617
+
618
+ do_simplify (modified_condition);
619
+ modified_condition = state.rename (std::move (modified_condition), ns);
620
+ do_simplify (modified_condition);
621
+
622
+ if (value_set_for_true_case && modified_condition.is_false ())
623
+ {
624
+ value_sett::entryt *entry = const_cast <value_sett::entryt *>(
625
+ value_set_for_true_case->get_entry_for_symbol (
626
+ symbol_expr_l1.get_identifier (), ns.follow (symbol_type), " " ));
627
+ value_set_for_true_case->erase_value_from_entry (*entry, possible_value);
628
+ }
629
+ else if (value_set_for_false_case && modified_condition.is_true ())
630
+ {
631
+ value_sett::entryt *entry = const_cast <value_sett::entryt *>(
632
+ value_set_for_false_case->get_entry_for_symbol (
633
+ symbol_expr_l1.get_identifier (), ns.follow (symbol_type), " " ));
634
+ value_set_for_false_case->erase_value_from_entry (
635
+ *entry, possible_value);
636
+ }
637
+ }
638
+ }
639
+ }
0 commit comments