Skip to content

Commit 8152899

Browse files
committed
When widening value-sets, only do a limited compact
Only collapse constants or intervals which overlap the extended upper or lower bound. Don't perform a general compact, unless the set has become large.
1 parent 70aa297 commit 8152899

File tree

4 files changed

+102
-29
lines changed

4 files changed

+102
-29
lines changed

regression/goto-analyzer/loop-termination-ne/test-unwind-5-value-sets.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ main.c
44
^EXIT=0$
55
^SIGNAL=0$
66
^main::1::1::i .* value-set-begin: 5 :value-set-end @ \[6\]
7-
^main::1::p .* value-set-begin: 2, \[11, 1F9\] :value-set-end @ \[5\]
7+
^main::1::p .* value-set-begin: 2, \[11, 21\], \[20, 1F9\] :value-set-end @ \[5\]
88
--

scripts/expected_doxygen_warnings.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
warning: Include graph for 'goto_instrument_parse_options.cpp' not generated, too many nodes (93), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
22
warning: Included by graph for 'goto_model.h' not generated, too many nodes (95), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3-
warning: Included by graph for 'arith_tools.h' not generated, too many nodes (167), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3+
warning: Included by graph for 'arith_tools.h' not generated, too many nodes (168), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
44
warning: Included by graph for 'c_types.h' not generated, too many nodes (128), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
55
warning: Included by graph for 'config.h' not generated, too many nodes (78), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
66
warning: Included by graph for 'invariant.h' not generated, too many nodes (172), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.

src/analyses/variable-sensitivity/value_set_abstract_object.cpp

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
/// \file
1010
/// Value Set Abstract Object
1111

12-
#include "interval_abstract_value.h"
1312
#include <analyses/variable-sensitivity/constant_abstract_value.h>
1413
#include <analyses/variable-sensitivity/context_abstract_object.h>
14+
#include <analyses/variable-sensitivity/interval_abstract_value.h>
1515
#include <analyses/variable-sensitivity/value_set_abstract_object.h>
1616

17+
#include <util/arith_tools.h>
1718
#include <util/make_unique.h>
19+
#include <util/simplify_expr.h>
1820

1921
#include "abstract_environment.h"
2022

@@ -114,9 +116,8 @@ maybe_extract_single_value(const abstract_object_pointert &maybe_singleton);
114116
static bool are_any_top(const abstract_object_sett &set);
115117

116118
static abstract_object_sett compact_values(const abstract_object_sett &values);
117-
static abstract_object_sett
118-
non_destructive_compact(const abstract_object_sett &values);
119119
static abstract_object_sett widen_value_set(
120+
const abstract_object_sett &values,
120121
const constant_interval_exprt &lhs,
121122
const constant_interval_exprt &rhs);
122123

@@ -227,8 +228,8 @@ abstract_object_pointert value_set_abstract_objectt::merge_with_value(
227228
widen_mode == widen_modet::could_widen && has_values(shared_from_this()) &&
228229
has_values(other))
229230
{
230-
union_values.insert(widen_value_set(to_interval(), other->to_interval()));
231-
union_values = non_destructive_compact(union_values);
231+
union_values =
232+
widen_value_set(union_values, to_interval(), other->to_interval());
232233
}
233234

234235
return resolve_values(union_values);
@@ -389,6 +390,9 @@ static abstract_object_sett compact_values(const abstract_object_sett &values)
389390

390391
static exprt eval_expr(const exprt &e);
391392
static bool is_le(const exprt &lhs, const exprt &rhs);
393+
static abstract_object_sett collapse_values_in_intervals(
394+
const abstract_object_sett &values,
395+
const std::vector<constant_interval_exprt> &intervals);
392396
static void
393397
collapse_overlapping_intervals(std::vector<constant_interval_exprt> &intervals);
394398

@@ -447,24 +451,31 @@ non_destructive_compact(const abstract_object_sett &values)
447451
if(intervals.empty())
448452
return values;
449453

450-
auto compacted = abstract_object_sett{};
454+
return collapse_values_in_intervals(values, intervals);
455+
}
456+
457+
static abstract_object_sett collapse_values_in_intervals(
458+
const abstract_object_sett &values,
459+
const std::vector<constant_interval_exprt> &intervals)
460+
{
461+
auto collapsed = abstract_object_sett{};
451462
// for each value, including the intervals
452463
// keep it if it is not in any of the intervals
453464
std::copy_if(
454465
values.begin(),
455466
values.end(),
456-
std::back_inserter(compacted),
467+
std::back_inserter(collapsed),
457468
[&intervals](const abstract_object_pointert &object) {
458469
return value_is_not_contained_in(object, intervals);
459470
});
460471
std::transform(
461472
intervals.begin(),
462473
intervals.end(),
463-
std::back_inserter(compacted),
474+
std::back_inserter(collapsed),
464475
[](const constant_interval_exprt &interval) {
465476
return interval_abstract_valuet::make_interval(interval);
466477
});
467-
return compacted;
478+
return collapsed;
468479
}
469480

470481
static abstract_object_sett
@@ -527,13 +538,14 @@ static bool is_le(const exprt &lhs, const exprt &rhs)
527538
}
528539

529540
static abstract_object_sett widen_value_set(
541+
const abstract_object_sett &values,
530542
const constant_interval_exprt &lhs,
531543
const constant_interval_exprt &rhs)
532544
{
533-
auto widened_ends = abstract_object_sett{};
534-
535545
if(lhs.contains(rhs))
536-
return widened_ends;
546+
return values;
547+
548+
auto widened_ends = std::vector<constant_interval_exprt>{};
537549

538550
auto lower_bound =
539551
constant_interval_exprt::get_min(lhs.get_lower(), rhs.get_lower());
@@ -548,19 +560,32 @@ static abstract_object_sett widen_value_set(
548560
// should extend lower bound?
549561
if(rhs.get_lower() < lhs.get_lower())
550562
{
551-
auto widened_lower_bound =
552-
simplify_expr(minus_exprt(lower_bound, range), ns);
553-
widened_ends.insert(interval_abstract_valuet::make_interval(
554-
constant_interval_exprt(widened_lower_bound, lower_bound)));
563+
auto widened_lower_bound = constant_interval_exprt(
564+
simplify_expr(minus_exprt(lower_bound, range), ns), lower_bound);
565+
widened_ends.push_back(widened_lower_bound);
566+
for(auto &obj : values)
567+
{
568+
auto value = std::dynamic_pointer_cast<const abstract_value_objectt>(obj);
569+
auto as_expr = value->to_interval();
570+
if(is_le(as_expr.get_lower(), lower_bound))
571+
widened_ends.push_back(as_expr);
572+
}
555573
}
556574
// should extend upper bound?
557575
if(lhs.get_upper() < rhs.get_upper())
558576
{
559-
auto widened_upper_bound =
560-
simplify_expr(plus_exprt(upper_bound, range), ns);
561-
widened_ends.insert(interval_abstract_valuet::make_interval(
562-
constant_interval_exprt(upper_bound, widened_upper_bound)));
577+
auto widened_upper_bound = constant_interval_exprt(
578+
upper_bound, simplify_expr(plus_exprt(upper_bound, range), ns));
579+
widened_ends.push_back(widened_upper_bound);
580+
for(auto &obj : values)
581+
{
582+
auto value = std::dynamic_pointer_cast<const abstract_value_objectt>(obj);
583+
auto as_expr = value->to_interval();
584+
if(is_le(upper_bound, as_expr.get_upper()))
585+
widened_ends.push_back(as_expr);
586+
}
563587
}
564588

565-
return widened_ends;
589+
collapse_overlapping_intervals(widened_ends);
590+
return collapse_values_in_intervals(values, widened_ends);
566591
}

unit/analyses/variable-sensitivity/value_set_abstract_object/widening_merge.cpp

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,19 +251,67 @@ SCENARIO(
251251
EXPECT_MODIFIED(merged, {interval_4minus_1, val2, val4, val4});
252252
}
253253
}
254-
/*
255-
WHEN("merging [2, 3] with [1, 5]")
254+
WHEN("merging {[1, 3]} with {2, 4}")
255+
{
256+
auto interval_1_3 = constant_interval_exprt(val1, val3);
257+
auto op1 = make_value_set(interval_1_3, environment, ns);
258+
auto op2 = make_value_set({val2, val4}, environment, ns);
259+
260+
auto merged = widening_merge(op1, op2);
261+
262+
THEN("widen upper-bound, {[1, 3], 2 [4, 8]}")
263+
{
264+
auto interval_4_8 = constant_interval_exprt(val4, val8);
265+
EXPECT_MODIFIED(merged, {interval_1_3, val2, interval_4_8});
266+
}
267+
}
268+
WHEN("merging {[1, 3]} with {[2, 4]}")
269+
{
270+
auto interval_1_3 = constant_interval_exprt(val1, val3);
271+
auto interval_2_4 = constant_interval_exprt(val2, val4);
272+
auto op1 = make_value_set(interval_1_3, environment, ns);
273+
auto op2 = make_value_set(interval_2_4, environment, ns);
274+
275+
auto merged = widening_merge(op1, op2);
276+
277+
THEN("widen upper-bound, {[1, 3], [2, 8]}")
278+
{
279+
auto interval_2_8 = constant_interval_exprt(val2, val8);
280+
EXPECT_MODIFIED(merged, {interval_1_3, interval_2_8});
281+
}
282+
}
283+
WHEN("merging {[2, 4]} with {1, 3}")
284+
{
285+
auto interval_2_4 = constant_interval_exprt(val2, val4);
286+
auto op1 = make_value_set(interval_2_4, environment, ns);
287+
auto op2 = make_value_set({val1, val3}, environment, ns);
288+
289+
auto merged = widening_merge(op1, op2);
290+
291+
THEN("widen lower bound - {[-3, 1], 3, [2, 4]}")
292+
{
293+
auto interval_3minus_1 =
294+
constant_interval_exprt(from_integer(-3, type), val1);
295+
EXPECT_MODIFIED(merged, {interval_2_4, val3, interval_3minus_1});
296+
}
297+
}
298+
WHEN("merging {[2, 4]} with {[1, 3]}")
256299
{
257-
auto op1 = make_value_set(val2, val3, environment, ns);
258-
auto op2 = make_value_set(val1, val5, environment, ns);
300+
auto interval_2_4 = constant_interval_exprt(val2, val4);
301+
auto interval_1_3 = constant_interval_exprt(val1, val3);
302+
auto op1 = make_value_set(interval_2_4, environment, ns);
303+
auto op2 = make_value_set(interval_1_3, environment, ns);
259304

260305
auto merged = widening_merge(op1, op2);
261306

262-
THEN("result is widen both bounds - [-4, 10]")
307+
THEN("widen lower bound - {[-3, 3], [2, 4]}")
263308
{
264-
EXPECT_MODIFIED(merged, val4minus, val10);
309+
auto interval_3minus_3 =
310+
constant_interval_exprt(from_integer(-3, type), val3);
311+
EXPECT_MODIFIED(merged, {interval_3minus_3, interval_2_4});
265312
}
266313
}
314+
/*
267315
WHEN("merging [-3, -1] with [-4, -2]")
268316
{
269317
auto op1 = make_value_set(val3minus, val1minus, environment, ns);

0 commit comments

Comments
 (0)