Skip to content

Commit 48acf78

Browse files
authored
Merge pull request #6190 from jezhiggins/vsd/widen-to-extreme
VSD - correct widening merge to handle extreme values
2 parents d52022d + 9815a7b commit 48acf78

File tree

7 files changed

+366
-42
lines changed

7 files changed

+366
-42
lines changed

src/analyses/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ SRC = ai.cpp \
5252
variable-sensitivity/variable_sensitivity_dependence_graph.cpp \
5353
variable-sensitivity/variable_sensitivity_domain.cpp \
5454
variable-sensitivity/variable_sensitivity_object_factory.cpp \
55+
variable-sensitivity/widened_range.cpp \
5556
variable-sensitivity/write_location_context.cpp \
5657
variable-sensitivity/write_stack.cpp \
5758
variable-sensitivity/write_stack_entry.cpp \

src/analyses/variable-sensitivity/interval_abstract_value.cpp

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "abstract_environment.h"
1818
#include "abstract_object_statistics.h"
1919
#include "interval_abstract_value.h"
20+
#include "widened_range.h"
2021

2122
static index_range_implementation_ptrt make_interval_index_range(
2223
const constant_interval_exprt &interval,
@@ -350,27 +351,11 @@ abstract_object_pointert widening_merge(
350351
const constant_interval_exprt &lhs,
351352
const constant_interval_exprt &rhs)
352353
{
353-
auto lower_bound =
354-
constant_interval_exprt::get_min(lhs.get_lower(), rhs.get_lower());
355-
auto upper_bound =
356-
constant_interval_exprt::get_max(lhs.get_upper(), rhs.get_upper());
357-
auto range = plus_exprt(
358-
minus_exprt(upper_bound, lower_bound), from_integer(1, lhs.type()));
359-
360-
auto dummy_symbol_table = symbol_tablet{};
361-
auto dummy_namespace = namespacet{dummy_symbol_table};
362-
363-
// should extend lower bound?
364-
if(rhs.get_lower() < lhs.get_lower())
365-
lower_bound =
366-
simplify_expr(minus_exprt(lower_bound, range), dummy_namespace);
367-
// should extend upper bound?
368-
if(lhs.get_upper() < rhs.get_upper())
369-
upper_bound =
370-
simplify_expr(plus_exprt(upper_bound, range), dummy_namespace);
354+
auto widened = widened_ranget(lhs, rhs);
371355

372356
// new interval ...
373-
auto new_interval = constant_interval_exprt(lower_bound, upper_bound);
357+
auto new_interval = constant_interval_exprt(
358+
widened.widened_lower_bound, widened.widened_upper_bound);
374359
return interval_abstract_valuet::make_interval(new_interval);
375360
}
376361

src/analyses/variable-sensitivity/value_set_abstract_object.cpp

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <analyses/variable-sensitivity/context_abstract_object.h>
1515
#include <analyses/variable-sensitivity/interval_abstract_value.h>
1616
#include <analyses/variable-sensitivity/value_set_abstract_object.h>
17+
#include <analyses/variable-sensitivity/widened_range.h>
1718

1819
#include <util/arith_tools.h>
1920
#include <util/make_unique.h>
@@ -414,6 +415,7 @@ static abstract_object_sett compact_values(const abstract_object_sett &values)
414415
}
415416

416417
static exprt eval_expr(const exprt &e);
418+
static bool is_eq(const exprt &lhs, const exprt &rhs);
417419
static bool is_le(const exprt &lhs, const exprt &rhs);
418420
static abstract_object_sett collapse_values_in_intervals(
419421
const abstract_object_sett &values,
@@ -446,6 +448,8 @@ void collapse_overlapping_intervals(
446448
intervals.begin(),
447449
intervals.end(),
448450
[](constant_interval_exprt const &lhs, constant_interval_exprt const &rhs) {
451+
if(is_eq(lhs.get_lower(), rhs.get_lower()))
452+
return is_le(lhs.get_upper(), rhs.get_upper());
449453
return is_le(lhs.get_lower(), rhs.get_lower());
450454
});
451455

@@ -556,10 +560,14 @@ static exprt eval_expr(const exprt &e)
556560
return simplify_expr(e, ns);
557561
}
558562

563+
static bool is_eq(const exprt &lhs, const exprt &rhs)
564+
{
565+
return constant_interval_exprt::equal(lhs, rhs);
566+
}
567+
559568
static bool is_le(const exprt &lhs, const exprt &rhs)
560569
{
561-
auto is_le_expr = binary_relation_exprt(lhs, ID_le, rhs);
562-
return eval_expr(is_le_expr).is_true();
570+
return constant_interval_exprt::less_than_or_equal(lhs, rhs);
563571
}
564572

565573
static abstract_object_sett widen_value_set(
@@ -572,41 +580,34 @@ static abstract_object_sett widen_value_set(
572580

573581
auto widened_ends = std::vector<constant_interval_exprt>{};
574582

575-
auto lower_bound =
576-
constant_interval_exprt::get_min(lhs.get_lower(), rhs.get_lower());
577-
auto upper_bound =
578-
constant_interval_exprt::get_max(lhs.get_upper(), rhs.get_upper());
579-
auto range = plus_exprt(
580-
minus_exprt(upper_bound, lower_bound), from_integer(1, lhs.type()));
581-
582-
auto symbol_table = symbol_tablet{};
583-
auto ns = namespacet{symbol_table};
583+
auto range = widened_ranget(lhs, rhs);
584584

585585
// should extend lower bound?
586-
if(rhs.get_lower() < lhs.get_lower())
586+
if(range.is_lower_widened)
587587
{
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);
588+
auto extended_lower_bound =
589+
constant_interval_exprt(range.widened_lower_bound, range.lower_bound);
590+
591+
widened_ends.push_back(extended_lower_bound);
591592
for(auto &obj : values)
592593
{
593594
auto value = std::dynamic_pointer_cast<const abstract_value_objectt>(obj);
594595
auto as_expr = value->to_interval();
595-
if(is_le(as_expr.get_lower(), lower_bound))
596+
if(is_le(as_expr.get_lower(), range.lower_bound))
596597
widened_ends.push_back(as_expr);
597598
}
598599
}
599600
// should extend upper bound?
600-
if(lhs.get_upper() < rhs.get_upper())
601+
if(range.is_upper_widened)
601602
{
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);
603+
auto extended_upper_bound =
604+
constant_interval_exprt(range.upper_bound, range.widened_upper_bound);
605+
widened_ends.push_back(extended_upper_bound);
605606
for(auto &obj : values)
606607
{
607608
auto value = std::dynamic_pointer_cast<const abstract_value_objectt>(obj);
608609
auto as_expr = value->to_interval();
609-
if(is_le(upper_bound, as_expr.get_upper()))
610+
if(is_le(range.upper_bound, as_expr.get_upper()))
610611
widened_ends.push_back(as_expr);
611612
}
612613
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*******************************************************************\
2+
3+
Module: helper for extending intervals during widening merges
4+
5+
Author: Jez Higgins
6+
7+
\*******************************************************************/
8+
9+
#include "widened_range.h"
10+
#include <util/simplify_expr.h>
11+
12+
static bool has_underflowed(const exprt &value)
13+
{
14+
return constant_interval_exprt::greater_than(
15+
value, from_integer(0, value.type()));
16+
}
17+
static bool has_overflowed(const exprt &value, const exprt &initial_value)
18+
{
19+
return constant_interval_exprt::less_than(value, initial_value);
20+
}
21+
22+
exprt widened_ranget::widen_lower_bound() const
23+
{
24+
if(!is_lower_widened)
25+
return lower_bound;
26+
27+
auto new_lower_bound = simplify_expr(minus_exprt(lower_bound, range_), ns_);
28+
29+
if(
30+
constant_interval_exprt::contains_extreme(new_lower_bound) ||
31+
has_underflowed(new_lower_bound))
32+
return min_exprt(lower_bound.type());
33+
34+
return new_lower_bound;
35+
}
36+
37+
exprt widened_ranget::widen_upper_bound() const
38+
{
39+
if(!is_upper_widened)
40+
return upper_bound;
41+
42+
auto new_upper_bound = simplify_expr(plus_exprt(upper_bound, range_), ns_);
43+
44+
if(
45+
constant_interval_exprt::contains_extreme(new_upper_bound) ||
46+
has_overflowed(new_upper_bound, upper_bound))
47+
return max_exprt(upper_bound.type());
48+
49+
return new_upper_bound;
50+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*******************************************************************\
2+
3+
Module: helper for extending intervals during widening merges
4+
5+
Author: Jez Higgins
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_WIDENED_RANGE_H
10+
#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_WIDENED_RANGE_H
11+
12+
#include <util/arith_tools.h>
13+
#include <util/interval.h>
14+
#include <util/namespace.h>
15+
#include <util/symbol_table.h>
16+
17+
class widened_ranget
18+
{
19+
public:
20+
widened_ranget(
21+
const constant_interval_exprt &lhs,
22+
const constant_interval_exprt &rhs)
23+
: is_lower_widened(
24+
constant_interval_exprt::less_than(rhs.get_lower(), lhs.get_lower())),
25+
is_upper_widened(
26+
constant_interval_exprt::less_than(lhs.get_upper(), rhs.get_upper())),
27+
lower_bound(
28+
constant_interval_exprt::get_min(lhs.get_lower(), rhs.get_lower())),
29+
upper_bound(
30+
constant_interval_exprt::get_max(lhs.get_upper(), rhs.get_upper())),
31+
ns_(symbol_tablet{}),
32+
range_(plus_exprt(
33+
minus_exprt(upper_bound, lower_bound),
34+
from_integer(1, lhs.type()))),
35+
widened_lower_bound(widen_lower_bound()),
36+
widened_upper_bound(widen_upper_bound())
37+
{
38+
}
39+
40+
const bool is_lower_widened;
41+
const bool is_upper_widened;
42+
const exprt lower_bound;
43+
const exprt upper_bound;
44+
45+
private:
46+
namespacet ns_;
47+
exprt range_;
48+
49+
public:
50+
const exprt widened_lower_bound;
51+
const exprt widened_upper_bound;
52+
53+
private:
54+
exprt widen_lower_bound() const;
55+
exprt widen_upper_bound() const;
56+
};
57+
58+
#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_WIDENED_RANGE_H

0 commit comments

Comments
 (0)