-
Notifications
You must be signed in to change notification settings - Fork 277
VSD: Simplifying abstract_objectt::write, collapsing inheritance hierarchy #5755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
ec33346
to
b27896b
Compare
Codecov Report
@@ Coverage Diff @@
## develop #5755 +/- ##
===========================================
+ Coverage 69.64% 69.67% +0.02%
===========================================
Files 1248 1242 -6
Lines 100911 100875 -36
===========================================
- Hits 70284 70282 -2
+ Misses 30627 30593 -34
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
3c4977a
to
5a328d4
Compare
5a328d4
to
b618d2e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any immediate show stoppers but this is quite a substantial refactor and it would be good to work through the code-base with you before we merge this PR.
else if( | ||
simplified_id == ID_array || simplified_id == ID_struct || | ||
simplified_id == ID_constant) | ||
simplified_id == ID_constant || simplified_id == ID_address_of) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is true that it is handled the same but it is for quite different reasons. This is not necessarily a problem, but it is something to be aware of.
|
||
class member_exprt; | ||
|
||
template<class aggregate_typet, class aggregate_traitst> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably a bit more template-y than we normally write but under the circumstances I can see this reduces an amount of duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's compile type polymorphism rather than run-time. We don't need, actually don't want, run-time polymorphism here.
merging_write); | ||
} | ||
else if( | ||
if( | ||
!index_interval.is_top() && !index_interval.is_bottom() && | ||
index_interval.get_lower().id() != ID_min && | ||
index_interval.get_upper().id() != ID_max) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although not touched by this PR, this case really should result in the interval being top.
} | ||
}; | ||
|
||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line?
|
||
#include <analyses/variable-sensitivity/abstract_object.h> | ||
|
||
class abstract_value_tag { }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow why this is needed...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd initially expected abstract_value_objectt
to be a template in a similar way to abstract_aggregate_objectt
. Didn't turn out that way, although may yet with the next bit of work. Happy to remove this now if you'd prefer.
if (is_top() || is_bottom() || interval.is_top() || interval.is_bottom()) | ||
return std::make_shared<empty_index_ranget>(); | ||
if (interval.get_lower().id() == ID_min || interval.get_upper().id() == ID_max) | ||
return std::make_shared<empty_index_ranget>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get that if the interval is bottom you should get an empty range but I'm not sure I get why this is the case for top or if the interval is open at one end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't make sense to me either, but this is the existing behaviour.
@@ -40,14 +40,18 @@ SCENARIO( | |||
} | |||
} | |||
|
|||
GIVEN("a top constant's range is empty") | |||
GIVEN("a top constant's range is has a single nil expression") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it tis top then it should be everything so this is definitely an improvement but I'm not quite sure what the nil is supposed to describe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The index_range is only used to during array access, and this supports the existing behaviour. Returning a nil expression here takes us down to https://github.com/jezhiggins/cbmc/blob/b618d2e3703434aa0cfb4d1c991c867b1dea9955/src/analyses/variable-sensitivity/full_array_abstract_object.cpp#L298
It is a special case, but it's isolated here rather than having to be explicitly handed in potentially several places elsewhere. As we look to expand other value representations, the more we can keep within those representations, the better.
@@ -443,18 +443,6 @@ class abstract_objectt : public std::enable_shared_from_this<abstract_objectt> | |||
/// abstraction anyway | |||
bool should_use_base_meet(const abstract_object_pointert &other) const; | |||
|
|||
template <class keyt> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good tidy up.
@@ -272,113 +270,137 @@ abstract_object_pointert full_array_abstract_objectt::write_element( | |||
environment, ns, stack, expr, value, merging_write); | |||
} | |||
|
|||
if(!stack.empty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not entirely clear to me why this is needed. Can't you just delegate the write to the relevant abstract_object
and then update the relevant entry with whatever it returns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because once we get to the end of the stack we need to worry about whether it's a merging write or not. Higher up the stack, we don't need to do that.
We have a similar decision point in full_struct_abstract_objectt
, and I assume we'll have one in our union representation when we fill that out. When we get there, it's entirely possible we'll be able to collapse the implementations.
@@ -376,13 +376,10 @@ abstract_object_pointert full_array_abstract_objectt::write_leaf_element( | |||
} | |||
else | |||
{ | |||
auto const old_value = result->map.find(index_value); | |||
auto old_value = result->map.find(index_value); | |||
if(old_value.has_value()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may not change the value that is stored but breaking sharing is a serious concern. Please check that the sharing map does actually handle that case correctly.
b618d2e
to
82d5dfa
Compare
I've had a discussion with @jezhiggins and I am in favour of merging this because:
|
d134e80
to
6c5f28a
Compare
@tautschnig @peterschrammel This is part of the refactor and tidy up of VSD. I don't expect you to look at that part of the commit, i think it is a net improvement and there is more to do. Please could you have a look at the changes in other parts of the tree, notably `util/' which are blocking the merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some administrative comments only, I have browsed (but not properly reviewed) the code in analyses/ and focussed on the single change in src/util/ only.
#include <util/pointer_expr.h> | ||
#include <language_util.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems surprising?
@@ -14,7 +14,7 @@ | |||
#include <analyses/variable-sensitivity/two_value_struct_abstract_object.h> | |||
#include <analyses/variable-sensitivity/variable_sensitivity_object_factory.h> | |||
#include <util/pointer_expr.h> | |||
#include <language_util.h> | |||
#include <langapi/language_util.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this file being included?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question - looking at now, I probably included for some debug/dev code which didn't need to be committed. I'll tidy this up.
@@ -0,0 +1,53 @@ | |||
#include <analyses/variable-sensitivity/abstract_environment.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quoting CODING_GUIDELINES.md
: "Each source and header file must start with a comment block stating the author."
@@ -0,0 +1,47 @@ | |||
#include <analyses/variable-sensitivity/abstract_value_object.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See earlier comment: please make sure all files include a header stating the author.
@@ -14,6 +14,12 @@ | |||
|
|||
#include "full_array_abstract_object.h" | |||
|
|||
bool eval_index( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should likely be static
as only required within this file.
sorted_viewt get_sorted_view() const | ||
{ | ||
sorted_viewt result; | ||
get_view(result); | ||
return result; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind adding documentation? It may be ok to put the three methods in a group, but there should be some sort of documentation.
static abstract_object_pointert merge( | ||
abstract_object_pointert op1, | ||
abstract_object_pointert op2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about changing the interface to make merge
return a pair?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did try it, but it didn't really make the code any clearer. If structured bindings were available, I'd absolutely have gone for it.
Each case returns, so there's no fall-through to further processing. Removing the _else if_ in favour of plain _if_ is functionally identical but with less visual clutter.
…set_abstract_object
…ay abstract_object
Reduced visibility, collapses common implementations, added factory methods.
Array representation is now independent of value representation. Renamed constant_array_abstract_object to full_array_abstract_object. Eliminated interval_array_abstract_object.
Not used in the code, and in any case now redundant as full_array_ works happily with value-sets.
…ether op1 was modified
if(value != abstract_object_pointert{old_value.value()}) I don't see that this test can ever fail, and even if it does the operation we're guarding against is benign
0b39442
to
d9f7b72
Compare
This PR simplifies the
write
member function implementation inabstract_objectt
subclasses. It collapses the inheritance hierarchy for classes modelling aggregate values (arrays, structs, unions), eliminating duplication.Several classes were named to better reflect their purpose - eg
union_abstract_objectt
becametwo_value_union_abstract_objectt
, and some new classes introduced to in place of a previously existing base class, egtwo_value_array_abstract_objectt
in place of the eliminatedarray_abtract_objectt
.This allowed further work to combine
interval_array_abstract_objectt
andconstant_array_abstract_objectt
together. The combined implementation has been renamedfull_array_abstract_objectt
, and the implementation refactored for reading comprehension.This PR is behaviour preserving. No need functionality is introduced.