@@ -140,13 +140,14 @@ void local_value_set_analysist::initialize(const goto_programt &fun)
140
140
// / \param declared_on_type: if not nil, filter by LHS object type
141
141
// / \param state: value set to search. Non-const as we will derive non-const
142
142
// / pointers into its internal data structures.
143
- // / \param [out] entrylist : extended with pointers into ` state.values` for each
144
- // / matching entry. Note the pointers are non-const.
143
+ // / \param [out] key_list : extended with keys in state.values for each matching
144
+ // / entry
145
145
static void get_all_field_value_sets (
146
146
const std::string &fieldname,
147
147
const typet &declared_on_type,
148
148
local_value_sett &state,
149
- std::vector<local_value_sett::entryt *> &entrylist)
149
+ const namespacet &ns,
150
+ std::vector<irep_idt> &key_list)
150
151
{
151
152
// Find all value sets we're currently aware of that may be affected by
152
153
// a write to the given field:
@@ -163,7 +164,7 @@ static void get_all_field_value_sets(
163
164
else if (entry.second .declared_on_type == declared_on_type)
164
165
include_this = true ;
165
166
if (include_this)
166
- entrylist .push_back (& entry.second );
167
+ key_list .push_back (entry.second . get_key (ns) );
167
168
}
168
169
}
169
170
}
@@ -407,12 +408,18 @@ void local_value_set_analysist::transform_function_stub(
407
408
408
409
std::map<exprt, local_value_sett::object_mapt> pre_call_rhs_value_sets;
409
410
411
+ local_value_sett::valuest weak_updates;
412
+ std::vector<std::pair<exprt, value_sett::object_mapt>> strong_updates;
413
+
410
414
for (const auto &assignment : assignments)
411
415
{
412
416
++nstub_assignments;
417
+
418
+ // First evaluate the right hand side of this assignment, with caching to
419
+ // avoid unnecessary recalculations
413
420
const auto &rhs_expr = assignment.second ;
414
- if (pre_call_rhs_value_sets.count (rhs_expr))
415
- continue ;
421
+ if (! pre_call_rhs_value_sets.count (rhs_expr))
422
+ {
416
423
value_sett::object_mapt &rhs_values = pre_call_rhs_value_sets[rhs_expr];
417
424
if (rhs_expr.id () == ID_external_value_set)
418
425
{
@@ -422,29 +429,31 @@ void local_value_set_analysist::transform_function_stub(
422
429
const std::string &evse_label =
423
430
id2string (to_constant_expr (evse.label ()).get_value ());
424
431
425
- if (has_prefix (evse_label, PER_FIELD_EVS_PREFIX))
426
- {
427
- PRECONDITION (evse.access_path_entries ().size () == 1 );
428
-
429
- // This external value set denotes either all pointers stored in a
430
- // particular field (e.g. TypeA.fieldb), or all arrays (in which case
431
- // declared_on_type() is nil the the field name is "[]")
432
- std::vector<local_value_sett::entryt *> rhs_entries;
433
- const auto &apback = evse.access_path_entries ().back ();
434
- if (!evse.is_initializer ())
432
+ if (has_prefix (evse_label, PER_FIELD_EVS_PREFIX))
435
433
{
436
- get_all_field_value_sets (
437
- id2string (apback.label ()),
438
- apback.declared_on_type (),
439
- valuesets,
440
- rhs_entries);
441
- }
442
-
443
- // Accumulate all possibly-read pointers into `rhs_values`:
444
- for (const auto &rhs_entry : rhs_entries)
445
- {
446
- valuesets.make_union_adjusting_types (
447
- rhs_values, rhs_entry->object_map , evse.type (), ns);
434
+ PRECONDITION (evse.access_path_entries ().size () == 1 );
435
+
436
+ // This external value set denotes either all pointers stored in a
437
+ // particular field (e.g. TypeA.fieldb), or all arrays (in which case
438
+ // declared_on_type() is nil the the field name is "[]")
439
+ std::vector<irep_idt> key_list;
440
+ const auto &apback = evse.access_path_entries ().back ();
441
+ if (!evse.is_initializer ())
442
+ {
443
+ get_all_field_value_sets (
444
+ id2string (apback.label ()),
445
+ apback.declared_on_type (),
446
+ valuesets,
447
+ ns,
448
+ key_list);
449
+ }
450
+
451
+ // Accumulate all possibly-read pointers into `rhs_values`:
452
+ for (const auto &key : key_list)
453
+ {
454
+ local_value_sett::entryt &entry = valuesets.values .at (key);
455
+ valuesets.make_union_adjusting_types (
456
+ rhs_values, entry.object_map , evse.type (), ns);
448
457
}
449
458
// Also add the external set itself,
450
459
// representing the possibility that the read
@@ -472,37 +481,37 @@ void local_value_set_analysist::transform_function_stub(
472
481
473
482
valuesets.get_value_set (root_object_expr, rhs_values, ns, false );
474
483
}
475
- }
476
- else
477
- {
478
- // Ordinary value set member (not an external value set);
479
-
480
- const auto rhs_num = valuesets.object_numbering .get_number (rhs_expr);
481
- if (can_cast_expr<dynamic_object_exprt>(rhs_expr) && rhs_num)
482
- {
483
- unsigned loc_number =
484
- expr_try_dynamic_cast<dynamic_object_exprt>(rhs_expr)->get_instance ();
485
- valuesets.demote_most_recent_dynamic_objects (loc_number);
486
484
}
485
+ else
486
+ {
487
+ // Ordinary value set member (not an external value set);
488
+
489
+ const auto rhs_num = valuesets.object_numbering .get_number (rhs_expr);
490
+ if (can_cast_expr<dynamic_object_exprt>(rhs_expr) && rhs_num)
491
+ {
492
+ unsigned loc_number =
493
+ expr_try_dynamic_cast<dynamic_object_exprt>(rhs_expr)
494
+ ->get_instance ();
495
+ valuesets.demote_most_recent_dynamic_objects (loc_number);
496
+ }
487
497
488
- valuesets.insert (rhs_values, rhs_expr);
498
+ valuesets.insert (rhs_values, rhs_expr);
499
+ }
489
500
}
490
- }
491
501
492
- // OK, all RHS sets have been read, now assign to the LHS symbols:
502
+ // Now calculate the left hand side of the assignment and store the update
503
+ // from the lhs to the rhs
493
504
494
- for (const auto &assignment : assignments)
495
- {
496
505
const auto &lhs_fieldname = assignment.first ;
497
- const auto &rhs_expr = assignment. second ;
498
- const auto &rhs_values = pre_call_rhs_value_sets.at (rhs_expr);
506
+ const value_sett::object_mapt &rhs_values =
507
+ pre_call_rhs_value_sets.at (rhs_expr);
499
508
500
509
if (has_prefix (lhs_fieldname.base_name , PER_FIELD_EVS_PREFIX))
501
510
{
502
511
// This writes to an external value set that denotes all fields with
503
512
// a particular name and declaring type.
504
513
// Apply the write to all matching local objects too:
505
- std::vector<local_value_sett::entryt *> lhs_entries ;
514
+ std::vector<irep_idt> key_list ;
506
515
507
516
const bool rhs_is_initializer_per_field_evs =
508
517
rhs_expr.id () == ID_external_value_set &&
@@ -515,7 +524,8 @@ void local_value_set_analysist::transform_function_stub(
515
524
lhs_fieldname.field_name ,
516
525
lhs_fieldname.declared_on_type ,
517
526
valuesets,
518
- lhs_entries);
527
+ ns,
528
+ key_list);
519
529
}
520
530
// Also write to the external value set itself, representing writes
521
531
// whose effects are external to this context too:
@@ -524,14 +534,17 @@ void local_value_set_analysist::transform_function_stub(
524
534
lhs_fieldname.field_name ,
525
535
lhs_fieldname.declared_on_type ,
526
536
lhs_fieldname.structured_lhs );
527
- std::string objkey = lhs_fieldname.base_name + lhs_fieldname.field_name ;
528
- auto insertit =
529
- valuesets.values .insert (std::make_pair (objkey, evse_entry));
530
- lhs_entries.push_back (&insertit.first ->second );
537
+ irep_idt objkey = evse_entry.get_key (ns);
538
+ valuesets.values .insert (std::make_pair (objkey, evse_entry));
539
+ key_list.emplace_back (objkey);
531
540
532
- // Apply the write to `state`:
533
- for (auto lhs_entry : lhs_entries)
534
- valuesets.make_union (lhs_entry->object_map , rhs_values);
541
+ // Store the write to `weak_updates`:
542
+ for (const irep_idt &key : key_list)
543
+ {
544
+ auto insert_it =
545
+ weak_updates.insert (std::make_pair (key, valuesets.values .at (key)));
546
+ valuesets.make_union (insert_it.first ->second .object_map , rhs_values);
547
+ }
535
548
}
536
549
else if (has_prefix (lhs_fieldname.base_name , PRECISE_EVS_PREFIX))
537
550
{
@@ -544,11 +557,9 @@ void local_value_set_analysist::transform_function_stub(
544
557
exprt lhs_expr = get_expr_from_precise_evs (
545
558
precise_evs, function_symbol, fcall, ns, *this );
546
559
547
- // Weak write - can we do strong writes?
548
- bool add_to_sets = true ;
549
- auto demoted_rhs_values = pre_call_rhs_value_sets.at (rhs_expr);
550
- valuesets.adjust_assign_rhs_values (rhs_expr, ns, demoted_rhs_values);
551
- valuesets.assign_valueset (lhs_expr, demoted_rhs_values, ns, add_to_sets);
560
+ strong_updates.emplace_back (lhs_expr, rhs_values);
561
+ valuesets.adjust_assign_rhs_values (
562
+ rhs_expr, ns, strong_updates.back ().second );
552
563
}
553
564
else if (has_prefix (lhs_fieldname.base_name , prefix_dynamic_object))
554
565
{
@@ -560,7 +571,7 @@ void local_value_set_analysist::transform_function_stub(
560
571
lhs_fieldname.declared_on_type ,
561
572
lhs_fieldname.structured_lhs );
562
573
auto insertit =
563
- valuesets. values .insert (std::make_pair (objkey, dynobj_entry_name));
574
+ weak_updates .insert (std::make_pair (objkey, dynobj_entry_name));
564
575
valuesets.make_union (insertit.first ->second .object_map , rhs_values);
565
576
}
566
577
else
@@ -569,15 +580,40 @@ void local_value_set_analysist::transform_function_stub(
569
580
// variables. Global variables defined in the java source cannot be
570
581
// structs and thus will have an empty string as the field name, but
571
582
// this is not true for synthetic global variables, such as class models.
572
- local_value_sett::entryt global_entry_name (
583
+ local_value_sett::entryt global_entry (
573
584
lhs_fieldname.base_name ,
574
585
lhs_fieldname.field_name ,
575
586
lhs_fieldname.declared_on_type ,
576
587
lhs_fieldname.structured_lhs );
577
- auto &global_entry = valuesets.get_entry (global_entry_name, ns);
578
- valuesets.make_union (global_entry.object_map , rhs_values);
588
+ auto insert_it = weak_updates.insert (
589
+ std::make_pair (global_entry.get_key (ns), global_entry));
590
+
591
+ valuesets.make_union (insert_it.first ->second .object_map , rhs_values);
579
592
}
580
593
}
594
+
595
+ // Now apply the updates. We have to be careful that parameters might alias,
596
+ // so we have to deal with strong updates in a slightly roundabout way. We
597
+ // first write an empty object map to expr which got a strong update. If the
598
+ // expr is singular then this will erase the object map. Then we write the
599
+ // intended object map with `add_to_sets` false, so the write is weak. Then we
600
+ // apply the weak updates.
601
+ value_sett::object_mapt empty_object_map;
602
+ for (auto &strong_update : strong_updates)
603
+ {
604
+ const bool add_to_sets = false ;
605
+ valuesets.assign_valueset (
606
+ strong_update.first , empty_object_map, ns, add_to_sets);
607
+ }
608
+
609
+ for (auto &strong_update : strong_updates)
610
+ {
611
+ const bool add_to_sets = true ;
612
+ valuesets.assign_valueset (
613
+ strong_update.first , strong_update.second , ns, add_to_sets);
614
+ }
615
+
616
+ valuesets.make_union (weak_updates);
581
617
}
582
618
583
619
void local_value_set_analysist::save_summary (const goto_programt &goto_program)
0 commit comments