Skip to content

Commit edb2eb0

Browse files
author
owen-jones-diffblue
authored
Merge pull request diffblue#322 from diffblue/owen-jones-diffblue/merge-logic-for-precise-EVSs
merge logic for precise EVSs
2 parents 94e279c + 4e781c3 commit edb2eb0

File tree

4 files changed

+100
-23
lines changed

4 files changed

+100
-23
lines changed

src/pointer-analysis/local_value_set.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ class local_value_sett:public value_sett
2222
mutable unsigned int num_writes_to_field_of_external_object=0;
2323
mutable bool no_merges=true;
2424

25-
bool should_apply_precise_external_value_sets() const
25+
/// Determines whether we should export precise or per_field external value
26+
/// sets in function summaries.
27+
/// \return
28+
bool should_export_precise_external_value_sets() const
2629
{
2730
#ifdef DO_NOT_USE_PRECISE_EXTERNAL_VALUE_SETS
2831
return false;

src/pointer-analysis/local_value_set_analysis.cpp

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -427,25 +427,6 @@ void local_value_set_analysist::transform_function_stub(
427427
}
428428
else if(has_prefix(lhs_fieldname.base_name, precise_evs_prefix))
429429
{
430-
std::vector<std::string> suffix_vec;
431-
/// Split the field name into individual field dereferences, so ".x.y"
432-
/// turns into ['.x', '.y']
433-
const char delim='.';
434-
std::string::const_iterator start=lhs_fieldname.field_name.begin();
435-
for(
436-
std::string::const_iterator it
437-
=std::next(lhs_fieldname.field_name.begin());
438-
it!=lhs_fieldname.field_name.end();
439-
++it)
440-
{
441-
if(*it==delim)
442-
{
443-
suffix_vec.emplace_back(start, it);
444-
start=it;
445-
}
446-
}
447-
suffix_vec.emplace_back(start, lhs_fieldname.field_name.end());
448-
449430
const external_value_set_exprt::access_path_entriest
450431
&access_path_entries =
451432
to_external_value_set(lhs_fieldname.structured_lhs)
@@ -552,6 +533,88 @@ bool local_value_set_analysist::is_singular(const std::set<exprt> &values)
552533
return baset::is_singular(values);
553534
}
554535

536+
void local_value_set_analysist::operator()(const goto_programt &goto_program)
537+
{
538+
initialize(goto_program);
539+
/// This is a dummy variable that will always be empty because we handle
540+
/// function calls specially
541+
goto_functionst goto_functions;
542+
543+
while(true)
544+
{
545+
bool fixedpoint_changed_valuesets =
546+
static_analysis_baset::fixedpoint(goto_program, goto_functions);
547+
548+
if(!fixedpoint_changed_valuesets)
549+
break;
550+
551+
bool initializer_precise_evs_added =
552+
add_precise_evs_initializers(goto_program);
553+
554+
if(!initializer_precise_evs_added)
555+
break;
556+
}
557+
}
558+
559+
bool local_value_set_analysist::add_precise_evs_initializers(
560+
const goto_programt &goto_program)
561+
{
562+
const std::string precise_evs_prefix = PRECISE_EVS_PREFIX;
563+
bool any_changes = false;
564+
565+
for(locationt loc = goto_program.instructions.begin();
566+
loc != goto_program.instructions.end();
567+
++loc)
568+
{
569+
if(loc->incoming_edges.size() <= 1)
570+
continue;
571+
572+
/// At each place in the control flow graph where two or more paths join
573+
/// together, we look through all the predecessors and see which precise
574+
/// EVSs occur in the left hand sides of their domains.
575+
std::map<irep_idt, unsigned long> precise_evs_counts;
576+
577+
for(goto_programt::instructionst::const_iterator predecessor :
578+
loc->incoming_edges)
579+
{
580+
for(const auto &value : (*this)[predecessor].value_set.values)
581+
{
582+
const exprt &lhs = value.second.structured_lhs;
583+
584+
if(
585+
can_cast_expr<external_value_set_exprt>(lhs) &&
586+
to_external_value_set(lhs).get_external_value_set_type() ==
587+
external_value_set_typet::PRECISE)
588+
{
589+
++precise_evs_counts[value.first];
590+
}
591+
}
592+
}
593+
594+
/// For each precise EVSs which occurs in some predecessor but not
595+
/// all, we add a copy of the EVS with is_initializer set to true to the
596+
/// value-set at the join instruction, to account for the fact that there
597+
/// is a path to this point where it still has its initial value.
598+
for(const auto identifier_count : precise_evs_counts)
599+
{
600+
if(identifier_count.second < loc->incoming_edges.size())
601+
{
602+
local_value_sett &value_set = (*this)[loc].value_set;
603+
value_sett::entryt &entry = value_set.values[identifier_count.first];
604+
605+
external_value_set_exprt init_evs =
606+
to_external_value_set(entry.structured_lhs).as_initializer();
607+
608+
bool object_map_changed = value_set.insert(entry.object_map, init_evs);
609+
610+
if(object_map_changed)
611+
any_changes = true;
612+
}
613+
}
614+
}
615+
return any_changes;
616+
}
617+
555618
/// Finds expressions that are reachable from parameters or global variables
556619
/// according to a given value-set-analysis state. For example:
557620
///
@@ -631,7 +694,7 @@ void lvsaa_single_external_set_summaryt::from_final_state(
631694
// field ones. If this is not possible then we export per field ones
632695
// and not precise ones.
633696
const bool should_export_precise_evs=
634-
final_state.should_apply_precise_external_value_sets();
697+
final_state.should_export_precise_external_value_sets();
635698

636699
// Picks which value-set LHS expressions may be external to this function:
637700
for(auto it=final_state.values.begin();

src/pointer-analysis/local_value_set_analysis.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ class local_value_set_analysist
145145
/// \param goto_program: function under analysis
146146
virtual void initialize(const goto_programt &goto_program) override;
147147

148+
/// Overloads static_analysis_baset::operator(). Find the fixed point of
149+
/// the analysis, then add initial values for precise external value sets
150+
/// if needed. Repeat these two steps until one of them does not make any
151+
/// changes.
152+
/// \param goto_program: the program under analysis
153+
virtual void operator()(const goto_programt &goto_program) override;
154+
148155
/// Overrides static_analysist's default behaviour on reaching a callsite,
149156
/// resulting in a call to `transform_function_stub` instead.
150157
virtual bool should_enter_function(const irep_idt& f) override
@@ -219,6 +226,12 @@ class local_value_set_analysist
219226
/// Requests `static_analysist` to call `transform_function_stub` on a
220227
/// recursive function call, rather than ignoring the call as per default.
221228
virtual bool get_ignore_recursion() override { return false; }
229+
230+
/// Look for join points in the control flow graph and add initial values
231+
/// for precise external value sets to their value-sets if needed.
232+
/// \param goto_program: the program under analysis
233+
/// \return true if any value-sets were changed
234+
bool add_precise_evs_initializers(const goto_programt &goto_program);
222235
};
223236

224237
#endif

src/pointer-analysis/local_value_set_domain.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ class local_value_set_domaint:
1717
bool merge(const local_value_set_domaint &other, locationt to)
1818
{
1919
value_set.make_union_bookkeeping_data_structures(other.value_set);
20-
if(to->incoming_edges.size()>1)
21-
value_set.no_merges=false;
2220
return value_set.make_union(other.value_set);
2321
}
2422
};

0 commit comments

Comments
 (0)