Skip to content

Commit fcb73d7

Browse files
authored
Merge pull request #5979 from jezhiggins/vsd-widening
Vsd - merge values
2 parents 67505fb + b3baa40 commit fcb73d7

22 files changed

+1544
-450
lines changed

src/analyses/variable-sensitivity/abstract_object.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,10 @@ class abstract_objectt : public std::enable_shared_from_this<abstract_objectt>
456456
top = false;
457457
this->set_not_top_internal();
458458
}
459+
void set_not_bottom()
460+
{
461+
bottom = false;
462+
}
459463
};
460464

461465
struct abstract_hashert

src/analyses/variable-sensitivity/abstract_object_set.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,24 @@ void abstract_object_sett::output(
3737
join_strings(out, output_values.begin(), output_values.end(), ", ");
3838
}
3939

40-
abstract_object_pointert abstract_object_sett::to_interval()
40+
constant_interval_exprt abstract_object_sett::to_interval() const
4141
{
4242
PRECONDITION(!values.empty());
4343

44-
exprt lower_expr = first()->to_constant();
45-
exprt upper_expr = first()->to_constant();
44+
const auto &initial =
45+
std::dynamic_pointer_cast<const abstract_value_objectt>(first());
46+
47+
exprt lower_expr = initial->to_interval().get_lower();
48+
exprt upper_expr = initial->to_interval().get_upper();
4649
for(const auto &value : values)
4750
{
48-
const auto &value_expr = value->to_constant();
49-
lower_expr = constant_interval_exprt::get_min(lower_expr, value_expr);
50-
upper_expr = constant_interval_exprt::get_max(upper_expr, value_expr);
51+
const auto &v =
52+
std::dynamic_pointer_cast<const abstract_value_objectt>(value);
53+
const auto &value_expr = v->to_interval();
54+
lower_expr =
55+
constant_interval_exprt::get_min(lower_expr, value_expr.get_lower());
56+
upper_expr =
57+
constant_interval_exprt::get_max(upper_expr, value_expr.get_upper());
5158
}
52-
return std::make_shared<interval_abstract_valuet>(
53-
constant_interval_exprt(lower_expr, upper_expr));
59+
return constant_interval_exprt(lower_expr, upper_expr);
5460
}

src/analyses/variable-sensitivity/abstract_object_set.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,9 @@ class abstract_object_sett
8080
void
8181
output(std::ostream &out, const ai_baset &ai, const namespacet &ns) const;
8282

83-
/// Cast the set of values \p other_values to an interval.
84-
/// \param other_values: the value-set to be abstracted into an interval
85-
/// \return the interval-abstract-object containing \p other_values
86-
abstract_object_pointert to_interval();
83+
/// Calculate the set of values as an interval.
84+
/// \return the constant_interval_exprt bounding the values
85+
constant_interval_exprt to_interval() const;
8786

8887
private:
8988
value_sett values;

src/analyses/variable-sensitivity/abstract_value_object.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,11 +631,17 @@ class value_set_evaluator
631631
auto unwrapped_values = unwrap_and_extract_values(new_values);
632632

633633
if(unwrapped_values.size() > value_set_abstract_objectt::max_value_set_size)
634-
return unwrapped_values.to_interval();
634+
return make_interval(unwrapped_values);
635635

636636
return make_value_set(unwrapped_values);
637637
}
638638

639+
static abstract_object_pointert
640+
make_interval(const abstract_object_sett &values)
641+
{
642+
return std::make_shared<interval_abstract_valuet>(values.to_interval());
643+
}
644+
639645
static abstract_object_pointert
640646
make_value_set(const abstract_object_sett &values)
641647
{

src/analyses/variable-sensitivity/abstract_value_object.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_VALUE_OBJECT_H
1414

1515
#include <analyses/variable-sensitivity/abstract_object.h>
16+
#include <util/interval.h>
1617

1718
class abstract_value_tag
1819
{
@@ -265,6 +266,8 @@ class abstract_value_objectt : public abstract_objectt,
265266
return value_ranget(value_range_implementation());
266267
}
267268

269+
virtual constant_interval_exprt to_interval() const = 0;
270+
268271
/// Interface for transforms
269272
///
270273
/// \param expr: the expression to evaluate and find the result of it.
@@ -291,4 +294,6 @@ class abstract_value_objectt : public abstract_objectt,
291294
value_range_implementation() const = 0;
292295
};
293296

294-
#endif
297+
using abstract_value_pointert = sharing_ptrt<const abstract_value_objectt>;
298+
299+
#endif

src/analyses/variable-sensitivity/constant_abstract_value.cpp

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ constant_abstract_valuet::constant_abstract_valuet(const typet &t)
4242
{
4343
}
4444

45+
constant_abstract_valuet::constant_abstract_valuet(const exprt &e)
46+
: abstract_value_objectt(e.type(), false, false), value(e)
47+
{
48+
}
49+
4550
constant_abstract_valuet::constant_abstract_valuet(
4651
const typet &t,
4752
bool tp,
@@ -86,6 +91,11 @@ exprt constant_abstract_valuet::to_constant() const
8691
}
8792
}
8893

94+
constant_interval_exprt constant_abstract_valuet::to_interval() const
95+
{
96+
return constant_interval_exprt(value, value);
97+
}
98+
8999
void constant_abstract_valuet::output(
90100
std::ostream &out,
91101
const ai_baset &ai,
@@ -104,38 +114,25 @@ void constant_abstract_valuet::output(
104114
abstract_object_pointert
105115
constant_abstract_valuet::merge(abstract_object_pointert other) const
106116
{
107-
constant_abstract_value_pointert cast_other =
108-
std::dynamic_pointer_cast<const constant_abstract_valuet>(other);
117+
auto cast_other =
118+
std::dynamic_pointer_cast<const abstract_value_objectt>(other);
109119
if(cast_other)
110-
{
111120
return merge_constant_constant(cast_other);
112-
}
113-
else
114-
{
115-
// TODO(tkiley): How do we set the result to be toppish? Does it matter?
116-
return abstract_objectt::merge(other);
117-
}
121+
122+
return abstract_objectt::merge(other);
118123
}
119124

120125
abstract_object_pointert constant_abstract_valuet::merge_constant_constant(
121-
const constant_abstract_value_pointert &other) const
126+
const abstract_value_pointert &other) const
122127
{
123-
if(is_bottom())
124-
{
125-
return std::make_shared<constant_abstract_valuet>(*other);
126-
}
127-
else
128-
{
129-
// Can we actually merge these value
130-
if(value == other->value)
131-
{
132-
return shared_from_this();
133-
}
134-
else
135-
{
136-
return abstract_objectt::merge(other);
137-
}
138-
}
128+
auto other_expr = other->to_constant();
129+
if(is_bottom() && other_expr.is_constant())
130+
return std::make_shared<constant_abstract_valuet>(other_expr);
131+
132+
if(value == other_expr) // Can we actually merge these value
133+
return shared_from_this();
134+
135+
return abstract_objectt::merge(other);
139136
}
140137

141138
void constant_abstract_valuet::get_statistics(

src/analyses/variable-sensitivity/constant_abstract_value.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,9 @@
1919

2020
class constant_abstract_valuet : public abstract_value_objectt
2121
{
22-
private:
23-
typedef sharing_ptrt<constant_abstract_valuet>
24-
constant_abstract_value_pointert;
25-
2622
public:
2723
explicit constant_abstract_valuet(const typet &t);
24+
explicit constant_abstract_valuet(const exprt &t);
2825
constant_abstract_valuet(const typet &t, bool tp, bool bttm);
2926
constant_abstract_valuet(
3027
const exprt &e,
@@ -39,6 +36,7 @@ class constant_abstract_valuet : public abstract_value_objectt
3936
value_range_implementation_ptrt value_range_implementation() const override;
4037

4138
exprt to_constant() const override;
39+
constant_interval_exprt to_interval() const override;
4240

4341
void output(
4442
std::ostream &out,
@@ -75,15 +73,15 @@ class constant_abstract_valuet : public abstract_value_objectt
7573
abstract_object_pointert merge(abstract_object_pointert other) const override;
7674

7775
private:
78-
/// Merges another constant abstract value into this one
76+
/// Merges another abstract value into this one
7977
///
8078
/// \param other: the abstract object to merge with
8179
///
8280
/// \return Returns a new abstract object that is the result of the merge
8381
/// unless the merge is the same as this abstract object, in which
8482
/// case it returns this.
8583
abstract_object_pointert
86-
merge_constant_constant(const constant_abstract_value_pointert &other) const;
84+
merge_constant_constant(const abstract_value_pointert &other) const;
8785

8886
exprt value;
8987
};

src/analyses/variable-sensitivity/interval_abstract_value.cpp

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,19 @@ exprt interval_abstract_valuet::to_constant() const
282282
#endif
283283
}
284284

285+
size_t interval_abstract_valuet::internal_hash() const
286+
{
287+
return std::hash<std::string>{}(interval.pretty());
288+
}
289+
290+
bool interval_abstract_valuet::internal_equality(
291+
const abstract_object_pointert &other) const
292+
{
293+
auto cast_other =
294+
std::dynamic_pointer_cast<const interval_abstract_valuet>(other);
295+
return cast_other && interval == cast_other->interval;
296+
}
297+
285298
void interval_abstract_valuet::output(
286299
std::ostream &out,
287300
const ai_baset &ai,
@@ -329,8 +342,8 @@ void interval_abstract_valuet::output(
329342
abstract_object_pointert
330343
interval_abstract_valuet::merge(abstract_object_pointert other) const
331344
{
332-
interval_abstract_value_pointert cast_other =
333-
std::dynamic_pointer_cast<const interval_abstract_valuet>(other);
345+
abstract_value_pointert cast_other =
346+
std::dynamic_pointer_cast<const abstract_value_objectt>(other);
334347
if(cast_other)
335348
{
336349
return merge_intervals(cast_other);
@@ -342,31 +355,31 @@ interval_abstract_valuet::merge(abstract_object_pointert other) const
342355
}
343356

344357
/// Merge another interval abstract object with this one
345-
/// \param other The interval abstract object to merge with
358+
/// \param other The abstract value object to merge with
346359
/// \return This if the other interval is subsumed by this,
347360
/// other if this is subsumed by other.
348361
/// Otherwise, a new interval abstract object
349362
/// with the smallest interval that subsumes both
350363
/// this and other
351-
abstract_object_pointert interval_abstract_valuet::merge_intervals(
352-
interval_abstract_value_pointert other) const
364+
abstract_object_pointert
365+
interval_abstract_valuet::merge_intervals(abstract_value_pointert &other) const
353366
{
354-
if(is_bottom() || other->interval.contains(interval))
355-
{
356-
return other;
357-
}
358-
else if(other->is_bottom() || interval.contains(other->interval))
359-
{
367+
if(other->is_bottom())
360368
return shared_from_this();
361-
}
362-
else
363-
{
364-
return std::make_shared<interval_abstract_valuet>(constant_interval_exprt(
365-
constant_interval_exprt::get_min(
366-
interval.get_lower(), other->interval.get_lower()),
367-
constant_interval_exprt::get_max(
368-
interval.get_upper(), other->interval.get_upper())));
369-
}
369+
370+
auto other_interval = other->to_interval();
371+
372+
if(is_bottom())
373+
return std::make_shared<interval_abstract_valuet>(other_interval);
374+
375+
if(interval.contains(other_interval))
376+
return shared_from_this();
377+
378+
return std::make_shared<interval_abstract_valuet>(constant_interval_exprt(
379+
constant_interval_exprt::get_min(
380+
interval.get_lower(), other_interval.get_lower()),
381+
constant_interval_exprt::get_max(
382+
interval.get_upper(), other_interval.get_upper())));
370383
}
371384

372385
abstract_object_pointert

src/analyses/variable-sensitivity/interval_abstract_value.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ class interval_abstract_valuet : public abstract_value_objectt
4141
value_range_implementation_ptrt value_range_implementation() const override;
4242

4343
exprt to_constant() const override;
44-
const constant_interval_exprt &to_interval() const
44+
constant_interval_exprt to_interval() const override
4545
{
4646
return interval;
4747
}
4848

49+
size_t internal_hash() const override;
50+
bool internal_equality(const abstract_object_pointert &other) const override;
51+
4952
void output(
5053
std::ostream &out,
5154
const class ai_baset &ai,
@@ -68,7 +71,7 @@ class interval_abstract_valuet : public abstract_value_objectt
6871
sharing_ptrt<interval_abstract_valuet>;
6972

7073
abstract_object_pointert
71-
merge_intervals(interval_abstract_value_pointert other) const;
74+
merge_intervals(abstract_value_pointert &other) const;
7275
abstract_object_pointert
7376
meet_intervals(interval_abstract_value_pointert other) const;
7477

src/analyses/variable-sensitivity/value_set_abstract_object.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/// \file
1010
/// Value Set Abstract Object
1111

12+
#include "interval_abstract_value.h"
1213
#include <analyses/variable-sensitivity/constant_abstract_value.h>
1314
#include <analyses/variable-sensitivity/context_abstract_object.h>
1415
#include <analyses/variable-sensitivity/two_value_array_abstract_object.h>
@@ -162,6 +163,25 @@ value_set_abstract_objectt::value_range_implementation() const
162163
return make_value_set_value_range(values);
163164
}
164165

166+
exprt value_set_abstract_objectt::to_constant() const
167+
{
168+
verify();
169+
170+
if(values.size() == 1)
171+
return values.first()->to_constant();
172+
173+
auto interval = to_interval();
174+
if(interval.is_single_value_interval())
175+
return interval.get_lower();
176+
177+
return abstract_objectt::to_constant();
178+
}
179+
180+
constant_interval_exprt value_set_abstract_objectt::to_interval() const
181+
{
182+
return values.to_interval();
183+
}
184+
165185
abstract_object_pointert value_set_abstract_objectt::write(
166186
abstract_environmentt &environment,
167187
const namespacet &ns,
@@ -199,7 +219,8 @@ abstract_object_pointert value_set_abstract_objectt::resolve_values(
199219

200220
if(unwrapped_values.size() > max_value_set_size)
201221
{
202-
return unwrapped_values.to_interval();
222+
return std::make_shared<interval_abstract_valuet>(
223+
unwrapped_values.to_interval());
203224
}
204225
//if(unwrapped_values.size() == 1)
205226
//{
@@ -215,19 +236,19 @@ abstract_object_pointert value_set_abstract_objectt::resolve_values(
215236
abstract_object_pointert
216237
value_set_abstract_objectt::merge(abstract_object_pointert other) const
217238
{
239+
auto union_values = !is_bottom() ? values : abstract_object_sett{};
240+
218241
auto other_value_set = std::dynamic_pointer_cast<const value_set_tag>(other);
219242
if(other_value_set)
220243
{
221-
auto union_values = values;
222244
union_values.insert(other_value_set->get_values());
223245
return resolve_values(union_values);
224246
}
225247

226248
auto other_value =
227-
std::dynamic_pointer_cast<const constant_abstract_valuet>(other);
249+
std::dynamic_pointer_cast<const abstract_value_objectt>(other);
228250
if(other_value)
229251
{
230-
auto union_values = values;
231252
union_values.insert(other_value);
232253
return resolve_values(union_values);
233254
}
@@ -254,6 +275,7 @@ void value_set_abstract_objectt::set_values(
254275
set_not_top();
255276
values = other_values;
256277
}
278+
set_not_bottom();
257279
verify();
258280
}
259281

0 commit comments

Comments
 (0)