Skip to content

Refactoring in goto_symex #3988

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

Merged

Conversation

romainbrenguier
Copy link
Contributor

@romainbrenguier romainbrenguier commented Jan 29, 2019

This are small refactoring commits in preparation for #3986

  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • [na] The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • [na] My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • [na] White-space or formatting changes outside the feature-related changed lines are in commits of their own.

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫
This PR failed Diffblue compatibility checks (cbmc commit: f47879d).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/98997921
Status will be re-evaluated on next push.
Please contact @peterschrammel, @thk123, or @allredj for support.

Common spurious failures:

  • the cbmc commit has disappeared in the mean time (e.g. in a force-push)
  • the author is not in the list of contributors (e.g. first-time contributors).

The incompatibility may have been introduced by an earlier PR. In that case merging this
PR should be avoided unless it fixes the current incompatibility.

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: c3bede4).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/99004545

Copy link
Collaborator

@martin-cs martin-cs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pointer-analysis changes seem fine. I am unsure about the value of moving to the functional "lots of small static function" from the OO "protected utility functions". This seems an issue of style and one that risks flip-flopping depending on who is working on the code. I'm not sure here is the place to have that discussion.

@@ -690,18 +690,15 @@ void goto_symex_statet::rename(
}
}

if(type.id()==ID_array)
if(const auto &array_type = type_try_dynamic_cast<array_typet>(type))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this fits more with the current way of doing things, so, yes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am no fan -- this doesn't improve execution speeds, but is less readable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It provides extra validation beyond just checking the id, which depends on the type you are casting to

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in favour of using type_try_dynamic_cast, because it means that you only need to know the name of the type you want to cast to, you don't need to know that the .id() is supposed to be ID_array for an array_typet, in order to do the cast. It also reduces the likely-hood of mismatches between the check and the cast. There is little chance of checking for ID_array and casting to bool_typet, when both operations are done by the try_cast. I would however be in favour of renaming type_try_dynamic_cast to something less verbose.

UNREACHABLE;
auto emplace_result = state.level1.current_names.emplace(
lhs.get_l1_object_identifier(), std::make_pair(lhs, 0));
CHECK_RETURN(emplace_result.second);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely.

Copy link
Member

@peterschrammel peterschrammel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favour of small static functions for a class that is not going to be inherited from. It makes the class interface easier to read (even if it is a drop in the ocean in goto-symex).

static void set_l2_indices(
symex_level0t level0,
symex_level1t level1,
symex_level2t level2,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please pass all these as const references? That will also show that their operator() should have been marked const (or maybe even static?), which will necessitate another commit to be added.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done and I've marked the operator const for symex_level1t, and replaced symex_level0t by a function so it doesn't need to be passed as an argument here.

/// When the type of the operands of a `with_exprt` or `if_exprt` have been
/// renamed they could end up being different from that of the expression. We
/// fix that by propagating the type of its operands to \p expr.
static void fix_type(exprt &expr)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do note that I consider this a workaround for a genuine bug, and I'd be curious to see what happens if instead of replacing we actually checked that the types already are consistent?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really not be necessary. We need to get rid of that renaming.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it doesn't seem necessary. I've tested adding a invariant that checks that this does not do anything and all tests in regression/cbmc passed so there doesn't seem to be a bug we need to workaround. I will remove that part.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a matter of procedure, would you mind just dropping the commit from this PR, and create a separate PR that removes that code and replaces it by the invariant you've played with? Thank you!!

Copy link
Contributor Author

@romainbrenguier romainbrenguier Jan 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made the PR there: #3993 and dropped the commit from here rebased this one on it

else
rhs=exprt(ID_invalid);
exprt rhs = [&]() -> exprt {
if(auto failed = get_failed_symbol(to_symbol_expr(code.symbol()), ns))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The to_symbol_expr is actually unnecessary, code.symbol() already returns a symbol_exprt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

@kroening kroening left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs another go -- I am in particularly concerned about the "renaming fix".

return ns.lookup(to_struct_tag_type(type)).type;
return {};
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be necessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you mean "renaming is never needed for tagged types," I think that's untrue when we have structs with a flexible array member to rename.

@@ -27,6 +27,14 @@ Author: Daniel Kroening, [email protected]

static void get_l1_name(exprt &expr);

static void set_l2_indices(
symex_level0t level0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented on the other PR, but can you explain the by-value passing here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reference was omitted by mistake, but this reveals that this level0 is actually constant, I going to replace the symex_level0t by a function

@romainbrenguier romainbrenguier force-pushed the refactor/symex-rename1 branch 2 times, most recently from f5d3a86 to 466b69a Compare January 30, 2019 11:31
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫
This PR failed Diffblue compatibility checks (cbmc commit: f5d3a86).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/99114133
Status will be re-evaluated on next push.
Please contact @peterschrammel, @thk123, or @allredj for support.

Common spurious failures:

  • the cbmc commit has disappeared in the mean time (e.g. in a force-push)
  • the author is not in the list of contributors (e.g. first-time contributors).

The incompatibility may have been introduced by an earlier PR. In that case merging this
PR should be avoided unless it fixes the current incompatibility.

@romainbrenguier romainbrenguier force-pushed the refactor/symex-rename1 branch 3 times, most recently from 51d7934 to c4d9ca4 Compare January 30, 2019 15:34
@tautschnig
Copy link
Collaborator

@kroening Is this looking better?

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: 02c7e5b).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/99164643

@romainbrenguier
Copy link
Contributor Author

@kroening

I don't see value in the static function refactoring; these do remind me too much of 90ies PASCAL.

I agree with @LAJW comment on that, plus it is generally recommended to make functions non-member whenever possible
(see http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197)
and it makes the other changes I want easier.

I am not a fan of the type_try_dynamic_cast idiom. At the very least it should be renamed, as 'dynamic_cast' has very specific meaning in C++.

See @NathanJPhillips comment on that, and renaming it would be outside the scope of this PR.

Two branches get replaced by a lambda; for most this reduces readability.

I removed these two lambda's.

The class hierarchy for the renaming levels is very intentional. I understand that the one that's replaced is trivial, but there's a point to the pattern.

I removed this commit, though I don't see the value of this, the inheritance is not used, and it initializes a map that is never used.

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: beb87d3).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/100460459

@peterschrammel
Copy link
Member

I don't see value in the static function refactoring; these do remind me too much of 90ies PASCAL.

That could be considered a matter of taste. But, still, there are clear advantages of using static functions:

  • it declutters class declarations, makes them shorter and easier to read, and reduces the size of header files, speeding up compilation.
  • it makes side effects explicit, making the code easier to understand, change and refactor (and trivial to refactor for reuse).

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: 569ecb6).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/100766529

@@ -231,32 +239,41 @@ void goto_symex_statet::assignment(
#endif
}

void goto_symex_statet::set_l0_indices(
static void set_l0_indices(
symex_level0t &level0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can surely be const

rename(type, l1_identifier, ns, level);
}
else if(type.id() == ID_union_tag)
else if(const auto &followed_type = type_of_symbol_or_tag(type, ns))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a reference

/// Return the type corresponding to a symbol or tag. Empty optional if \p type
/// is neither a symbol or a tag.
static optionalt<typet>
type_of_symbol_or_tag(const typet &type, const namespacet &ns)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could replace all this with type = ns.follow(type);, at the top of rename_type, as that's a no-op for non-tags.

return ns.lookup(to_struct_tag_type(type)).type;
return {};
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you mean "renaming is never needed for tagged types," I think that's untrue when we have structs with a flexible array member to rename.

@smowton
Copy link
Contributor

smowton commented Feb 14, 2019

If I were you I'd drop the static-ifcation and have the try_dynamic_cast vs. id() == fight elsewhere, that way this PR will be style-war free and easier to merge :)

@romainbrenguier
Copy link
Contributor Author

@smowton

If I were you I'd drop the static-ifcation and have the try_dynamic_cast vs. id() == fight elsewhere, that way this PR will be style-war free and easier to merge :)

I've dropped the dynamic_cast change, and applied your suggestion for the rename typet, but making the functions static is the main purpose of this PR.

@@ -688,6 +688,8 @@ void goto_symex_statet::rename(
const namespacet &ns,
levelt level)
{
type = ns.follow(type);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not even sure that compiles, but even when you make it compile: I think it should be done after requires_renaming to make sure we don't unnecessarily break sharing.

std::make_pair(lhs, 0))).second)
UNREACHABLE;
auto emplace_result = state.level1.current_names.emplace(
lhs.get_l1_object_identifier(), std::make_pair(lhs, 0));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until we have C++17 use:

auto emplace_result = state.level1.current_names.emplace(
  std::piecewise_construct,
  std::forward_as_tuple(lhs.get_l1_object_identifier()),
  std::forward_as_tuple(lhs, 0));

to avoid even constructing the second pair if the key already exists.

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫
This PR failed Diffblue compatibility checks (cbmc commit: 5e95d69).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/100977333
Status will be re-evaluated on next push.
Please contact @peterschrammel, @thk123, or @allredj for support.

Common spurious failures:

  • the cbmc commit has disappeared in the mean time (e.g. in a force-push)
  • the author is not in the list of contributors (e.g. first-time contributors).

The incompatibility may have been introduced by an earlier PR. In that case merging this
PR should be avoided unless it fixes the current incompatibility.

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: 5e95d69).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/100977333

Make obvious the operator doesn't change the state of the object.
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: 6bd85cf).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/101311049

@@ -675,6 +675,8 @@ void goto_symex_statet::rename(
if(!requires_renaming(type, ns))
return; // no action

type = ns.follow(type);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that not expanding some tag types?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentionally so, with the idea to replace the expansion below (lines 728ff have been removed). But I might be missing something.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok -- I'd move below the following if block, and then add a comment such as
// expand struct and union tag types

@smowton
Copy link
Contributor

smowton commented Feb 19, 2019

@romainbrenguier I talked to @kroening on Slack, he said this is ok once the ns.follow is moved below the if(...) immediately below it that may return the previously renamed type and therefore render the follow pointless.

This avoids a disjunction of cases for the different type of tags and
makes the rename function simpler.
Using emplace avoids a call to make_pair, and CHECK_RETURN is more
adapted to the situation were we check the return value of insert/emplace.
This is more precise on the type of object returned.
@romainbrenguier
Copy link
Contributor Author

@smowton @kroening done

@kroening
Copy link
Member

@romainbrenguier Many thanks for the extra effort!

@romainbrenguier romainbrenguier merged commit 55eec59 into diffblue:develop Feb 20, 2019
@romainbrenguier romainbrenguier deleted the refactor/symex-rename1 branch February 20, 2019 09:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.