Skip to content

Commit 4248f1b

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 39f1987 commit 4248f1b

File tree

3 files changed

+98
-27
lines changed

3 files changed

+98
-27
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
--

src/analyses/variable-sensitivity/value_set_abstract_object.cpp

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,8 @@ maybe_extract_single_value(const abstract_object_pointert &maybe_singleton);
117117
static bool are_any_top(const abstract_object_sett &set);
118118

119119
static abstract_object_sett compact_values(const abstract_object_sett &values);
120-
static abstract_object_sett
121-
non_destructive_compact(const abstract_object_sett &values);
122120
static abstract_object_sett widen_value_set(
121+
const abstract_object_sett &values,
123122
const constant_interval_exprt &lhs,
124123
const constant_interval_exprt &rhs);
125124

@@ -230,8 +229,8 @@ abstract_object_pointert value_set_abstract_objectt::merge_with_value(
230229
widen_mode == widen_modet::could_widen && has_values(shared_from_this()) &&
231230
has_values(other))
232231
{
233-
union_values.insert(widen_value_set(to_interval(), other->to_interval()));
234-
union_values = non_destructive_compact(union_values);
232+
union_values =
233+
widen_value_set(union_values, to_interval(), other->to_interval());
235234
}
236235

237236
return resolve_values(union_values);
@@ -416,6 +415,9 @@ static abstract_object_sett compact_values(const abstract_object_sett &values)
416415

417416
static exprt eval_expr(const exprt &e);
418417
static bool is_le(const exprt &lhs, const exprt &rhs);
418+
static abstract_object_sett collapse_values_in_intervals(
419+
const abstract_object_sett &values,
420+
const std::vector<constant_interval_exprt> &intervals);
419421
static void
420422
collapse_overlapping_intervals(std::vector<constant_interval_exprt> &intervals);
421423

@@ -474,24 +476,31 @@ non_destructive_compact(const abstract_object_sett &values)
474476
if(intervals.empty())
475477
return values;
476478

477-
auto compacted = abstract_object_sett{};
479+
return collapse_values_in_intervals(values, intervals);
480+
}
481+
482+
static abstract_object_sett collapse_values_in_intervals(
483+
const abstract_object_sett &values,
484+
const std::vector<constant_interval_exprt> &intervals)
485+
{
486+
auto collapsed = abstract_object_sett{};
478487
// for each value, including the intervals
479488
// keep it if it is not in any of the intervals
480489
std::copy_if(
481490
values.begin(),
482491
values.end(),
483-
std::back_inserter(compacted),
492+
std::back_inserter(collapsed),
484493
[&intervals](const abstract_object_pointert &object) {
485494
return value_is_not_contained_in(object, intervals);
486495
});
487496
std::transform(
488497
intervals.begin(),
489498
intervals.end(),
490-
std::back_inserter(compacted),
499+
std::back_inserter(collapsed),
491500
[](const constant_interval_exprt &interval) {
492501
return interval_abstract_valuet::make_interval(interval);
493502
});
494-
return compacted;
503+
return collapsed;
495504
}
496505

497506
static abstract_object_sett
@@ -554,13 +563,14 @@ static bool is_le(const exprt &lhs, const exprt &rhs)
554563
}
555564

556565
static abstract_object_sett widen_value_set(
566+
const abstract_object_sett &values,
557567
const constant_interval_exprt &lhs,
558568
const constant_interval_exprt &rhs)
559569
{
560-
auto widened_ends = abstract_object_sett{};
561-
562570
if(lhs.contains(rhs))
563-
return widened_ends;
571+
return values;
572+
573+
auto widened_ends = std::vector<constant_interval_exprt>{};
564574

565575
auto lower_bound =
566576
constant_interval_exprt::get_min(lhs.get_lower(), rhs.get_lower());
@@ -575,19 +585,32 @@ static abstract_object_sett widen_value_set(
575585
// should extend lower bound?
576586
if(rhs.get_lower() < lhs.get_lower())
577587
{
578-
auto widened_lower_bound =
579-
simplify_expr(minus_exprt(lower_bound, range), ns);
580-
widened_ends.insert(interval_abstract_valuet::make_interval(
581-
constant_interval_exprt(widened_lower_bound, lower_bound)));
588+
auto widened_lower_bound = constant_interval_exprt(
589+
simplify_expr(minus_exprt(lower_bound, range), ns), lower_bound);
590+
widened_ends.push_back(widened_lower_bound);
591+
for(auto &obj : values)
592+
{
593+
auto value = std::dynamic_pointer_cast<const abstract_value_objectt>(obj);
594+
auto as_expr = value->to_interval();
595+
if(is_le(as_expr.get_lower(), lower_bound))
596+
widened_ends.push_back(as_expr);
597+
}
582598
}
583599
// should extend upper bound?
584600
if(lhs.get_upper() < rhs.get_upper())
585601
{
586-
auto widened_upper_bound =
587-
simplify_expr(plus_exprt(upper_bound, range), ns);
588-
widened_ends.insert(interval_abstract_valuet::make_interval(
589-
constant_interval_exprt(upper_bound, widened_upper_bound)));
602+
auto widened_upper_bound = constant_interval_exprt(
603+
upper_bound, simplify_expr(plus_exprt(upper_bound, range), ns));
604+
widened_ends.push_back(widened_upper_bound);
605+
for(auto &obj : values)
606+
{
607+
auto value = std::dynamic_pointer_cast<const abstract_value_objectt>(obj);
608+
auto as_expr = value->to_interval();
609+
if(is_le(upper_bound, as_expr.get_upper()))
610+
widened_ends.push_back(as_expr);
611+
}
590612
}
591613

592-
return widened_ends;
614+
collapse_overlapping_intervals(widened_ends);
615+
return collapse_values_in_intervals(values, widened_ends);
593616
}

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)