Skip to content

Commit 956a631

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 1b3a017 commit 956a631

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 (79), 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 <algorithm>
2022

@@ -116,9 +118,8 @@ maybe_extract_single_value(const abstract_object_pointert &maybe_singleton);
116118
static bool are_any_top(const abstract_object_sett &set);
117119

118120
static abstract_object_sett compact_values(const abstract_object_sett &values);
119-
static abstract_object_sett
120-
non_destructive_compact(const abstract_object_sett &values);
121121
static abstract_object_sett widen_value_set(
122+
const abstract_object_sett &values,
122123
const constant_interval_exprt &lhs,
123124
const constant_interval_exprt &rhs);
124125

@@ -229,8 +230,8 @@ abstract_object_pointert value_set_abstract_objectt::merge_with_value(
229230
widen_mode == widen_modet::could_widen && has_values(shared_from_this()) &&
230231
has_values(other))
231232
{
232-
union_values.insert(widen_value_set(to_interval(), other->to_interval()));
233-
union_values = non_destructive_compact(union_values);
233+
union_values =
234+
widen_value_set(union_values, to_interval(), other->to_interval());
234235
}
235236

236237
return resolve_values(union_values);
@@ -391,6 +392,9 @@ static abstract_object_sett compact_values(const abstract_object_sett &values)
391392

392393
static exprt eval_expr(const exprt &e);
393394
static bool is_le(const exprt &lhs, const exprt &rhs);
395+
static abstract_object_sett collapse_values_in_intervals(
396+
const abstract_object_sett &values,
397+
const std::vector<constant_interval_exprt> &intervals);
394398
static void
395399
collapse_overlapping_intervals(std::vector<constant_interval_exprt> &intervals);
396400

@@ -449,24 +453,31 @@ non_destructive_compact(const abstract_object_sett &values)
449453
if(intervals.empty())
450454
return values;
451455

452-
auto compacted = abstract_object_sett{};
456+
return collapse_values_in_intervals(values, intervals);
457+
}
458+
459+
static abstract_object_sett collapse_values_in_intervals(
460+
const abstract_object_sett &values,
461+
const std::vector<constant_interval_exprt> &intervals)
462+
{
463+
auto collapsed = abstract_object_sett{};
453464
// for each value, including the intervals
454465
// keep it if it is not in any of the intervals
455466
std::copy_if(
456467
values.begin(),
457468
values.end(),
458-
std::back_inserter(compacted),
469+
std::back_inserter(collapsed),
459470
[&intervals](const abstract_object_pointert &object) {
460471
return value_is_not_contained_in(object, intervals);
461472
});
462473
std::transform(
463474
intervals.begin(),
464475
intervals.end(),
465-
std::back_inserter(compacted),
476+
std::back_inserter(collapsed),
466477
[](const constant_interval_exprt &interval) {
467478
return interval_abstract_valuet::make_interval(interval);
468479
});
469-
return compacted;
480+
return collapsed;
470481
}
471482

472483
static abstract_object_sett
@@ -529,13 +540,14 @@ static bool is_le(const exprt &lhs, const exprt &rhs)
529540
}
530541

531542
static abstract_object_sett widen_value_set(
543+
const abstract_object_sett &values,
532544
const constant_interval_exprt &lhs,
533545
const constant_interval_exprt &rhs)
534546
{
535-
auto widened_ends = abstract_object_sett{};
536-
537547
if(lhs.contains(rhs))
538-
return widened_ends;
548+
return values;
549+
550+
auto widened_ends = std::vector<constant_interval_exprt>{};
539551

540552
auto lower_bound =
541553
constant_interval_exprt::get_min(lhs.get_lower(), rhs.get_lower());
@@ -550,19 +562,32 @@ static abstract_object_sett widen_value_set(
550562
// should extend lower bound?
551563
if(rhs.get_lower() < lhs.get_lower())
552564
{
553-
auto widened_lower_bound =
554-
simplify_expr(minus_exprt(lower_bound, range), ns);
555-
widened_ends.insert(interval_abstract_valuet::make_interval(
556-
constant_interval_exprt(widened_lower_bound, lower_bound)));
565+
auto widened_lower_bound = constant_interval_exprt(
566+
simplify_expr(minus_exprt(lower_bound, range), ns), lower_bound);
567+
widened_ends.push_back(widened_lower_bound);
568+
for(auto &obj : values)
569+
{
570+
auto value = std::dynamic_pointer_cast<const abstract_value_objectt>(obj);
571+
auto as_expr = value->to_interval();
572+
if(is_le(as_expr.get_lower(), lower_bound))
573+
widened_ends.push_back(as_expr);
574+
}
557575
}
558576
// should extend upper bound?
559577
if(lhs.get_upper() < rhs.get_upper())
560578
{
561-
auto widened_upper_bound =
562-
simplify_expr(plus_exprt(upper_bound, range), ns);
563-
widened_ends.insert(interval_abstract_valuet::make_interval(
564-
constant_interval_exprt(upper_bound, widened_upper_bound)));
579+
auto widened_upper_bound = constant_interval_exprt(
580+
upper_bound, simplify_expr(plus_exprt(upper_bound, range), ns));
581+
widened_ends.push_back(widened_upper_bound);
582+
for(auto &obj : values)
583+
{
584+
auto value = std::dynamic_pointer_cast<const abstract_value_objectt>(obj);
585+
auto as_expr = value->to_interval();
586+
if(is_le(upper_bound, as_expr.get_upper()))
587+
widened_ends.push_back(as_expr);
588+
}
565589
}
566590

567-
return widened_ends;
591+
collapse_overlapping_intervals(widened_ends);
592+
return collapse_values_in_intervals(values, widened_ends);
568593
}

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
@@ -252,19 +252,67 @@ SCENARIO(
252252
EXPECT_MODIFIED(merged, {interval_4minus_1, val2, val4, val4});
253253
}
254254
}
255-
/*
256-
WHEN("merging [2, 3] with [1, 5]")
255+
WHEN("merging {[1, 3]} with {2, 4}")
256+
{
257+
auto interval_1_3 = constant_interval_exprt(val1, val3);
258+
auto op1 = make_value_set(interval_1_3, environment, ns);
259+
auto op2 = make_value_set({val2, val4}, environment, ns);
260+
261+
auto merged = widening_merge(op1, op2);
262+
263+
THEN("widen upper-bound, {[1, 3], 2 [4, 8]}")
264+
{
265+
auto interval_4_8 = constant_interval_exprt(val4, val8);
266+
EXPECT_MODIFIED(merged, {interval_1_3, val2, interval_4_8});
267+
}
268+
}
269+
WHEN("merging {[1, 3]} with {[2, 4]}")
270+
{
271+
auto interval_1_3 = constant_interval_exprt(val1, val3);
272+
auto interval_2_4 = constant_interval_exprt(val2, val4);
273+
auto op1 = make_value_set(interval_1_3, environment, ns);
274+
auto op2 = make_value_set(interval_2_4, environment, ns);
275+
276+
auto merged = widening_merge(op1, op2);
277+
278+
THEN("widen upper-bound, {[1, 3], [2, 8]}")
279+
{
280+
auto interval_2_8 = constant_interval_exprt(val2, val8);
281+
EXPECT_MODIFIED(merged, {interval_1_3, interval_2_8});
282+
}
283+
}
284+
WHEN("merging {[2, 4]} with {1, 3}")
285+
{
286+
auto interval_2_4 = constant_interval_exprt(val2, val4);
287+
auto op1 = make_value_set(interval_2_4, environment, ns);
288+
auto op2 = make_value_set({val1, val3}, environment, ns);
289+
290+
auto merged = widening_merge(op1, op2);
291+
292+
THEN("widen lower bound - {[-3, 1], 3, [2, 4]}")
293+
{
294+
auto interval_3minus_1 =
295+
constant_interval_exprt(from_integer(-3, type), val1);
296+
EXPECT_MODIFIED(merged, {interval_2_4, val3, interval_3minus_1});
297+
}
298+
}
299+
WHEN("merging {[2, 4]} with {[1, 3]}")
257300
{
258-
auto op1 = make_value_set(val2, val3, environment, ns);
259-
auto op2 = make_value_set(val1, val5, environment, ns);
301+
auto interval_2_4 = constant_interval_exprt(val2, val4);
302+
auto interval_1_3 = constant_interval_exprt(val1, val3);
303+
auto op1 = make_value_set(interval_2_4, environment, ns);
304+
auto op2 = make_value_set(interval_1_3, environment, ns);
260305

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

263-
THEN("result is widen both bounds - [-4, 10]")
308+
THEN("widen lower bound - {[-3, 3], [2, 4]}")
264309
{
265-
EXPECT_MODIFIED(merged, val4minus, val10);
310+
auto interval_3minus_3 =
311+
constant_interval_exprt(from_integer(-3, type), val3);
312+
EXPECT_MODIFIED(merged, {interval_3minus_3, interval_2_4});
266313
}
267314
}
315+
/*
268316
WHEN("merging [-3, -1] with [-4, -2]")
269317
{
270318
auto op1 = make_value_set(val3minus, val1minus, environment, ns);

0 commit comments

Comments
 (0)