Skip to content

Make return type of set_l*_indices be a renamedt [blocks: #4333] #3986

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 makes it easier to track through which kind of renaming the symbols have been through.
This is an intermediary step, for getting all renamed expression use this types (the next step would be to do the same for all the rename_* functions)

Edit: I have changed the title of the PR to better reflect its content now that it has been rebased on the preliminary PR introducing the renamedt type

  • Each commit message has a non-empty body, explaining why the change was made.
  • [na] 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
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.

This seems like quite a big step. How does this interact with the validity checks for programs, expressions, etc. that is being developed to capture those system invariants?

@@ -237,11 +237,13 @@ 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.

Should probably be by-ref?

}
}

ssa_exprt
goto_symex_statet::rename_level0(const symbol_exprt &expr, 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.

Shouldn't that be specifically an ssa_exprt, considering we still explicitly convert symbol_exprt -> ssa_exprt in rename_*?

@smowton
Copy link
Contributor

smowton commented Jan 30, 2019

I think the template argument for level0t et al would always have to be ssa_exprt, so I'd recommend just making these subclasses of exprt. Note I would keep the type-incompatibility of l0_ssa_exprt and l1_ssa_exprt, since it's important that an L1 expr can't be silently cast to an L0 expr.

@smowton
Copy link
Contributor

smowton commented Jan 30, 2019

@martin-cs these would presumably render such invariants unnecessary when we can enforce with the type system, similar to how we would pass a struct_typet around and not constantly re-verify that it meets the required structure of such a type (that was checked by to_struct_typet)

@romainbrenguier
Copy link
Contributor Author

@smowton

I think the template argument for level0t et al would always have to be ssa_exprt, so I'd recommend just making these subclasses of exprt. Note I would keep the type-incompatibility of l0_ssa_exprt and l1_ssa_exprt, since it's important that an L1 expr can't be silently cast to an L0 expr.

The argument sometimes needs to be exprt because for instance we have if_exprt or others which have been renamed. On the other hand ssa_exprt can only represent symbols.

@romainbrenguier romainbrenguier force-pushed the refactor/symex-rename branch 2 times, most recently from 6ebefbb to f13a946 Compare March 5, 2019 15:46
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: f13a946).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/103232156
Status will be re-evaluated on next push.
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 compatibility was already broken by an earlier merge.

@romainbrenguier romainbrenguier changed the title Introduce types for result of rename functions Make return type of set_l*_indices be a renamedt Mar 5, 2019

// in case we happen to be multi-threaded, record the memory access
bool is_shared=l2_thread_write_encoding(lhs, ns);
bool is_shared = l2_thread_write_encoding(l2_lhs.get(), ns);
Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems lhs == l2_lhs.get(), so why can't you just keep using lhs here (and below)?

!l0_expr.get().get_level_2().empty())
{
// TODO reaching here means the information that l0_expr was L1 or L2 has
// TODO been lost somewhere during execution, which should be avoided
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use UNREACHABLE (here and below)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately it is reachable. There are even cases where level 2 is set but not level 1.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Level 2 being set without level 1 is expected for objects with static lifetime, but maybe there are also actually buggy cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's good to know. I think it will be easier to see if something is done wrong once the renamedt type is used everywhere in goto_symex_state. (just to be clear, we do not change the behaviour here, the ignoring of the non-empty case was just done in the caller of this function).

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: d723b64).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/103247786
Status will be re-evaluated on next push.
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 compatibility was already broken by an earlier merge.

@romainbrenguier romainbrenguier mentioned this pull request Mar 6, 2019
4 tasks
@tautschnig
Copy link
Collaborator

  1. I think these commits either need squashing or forcibly updated dates - reviewing commit-by-commit on GitHub is not meaningful at the moment, and I'm also finding it very hard to figure out from the commit subjects where I might have to start.
  2. I don't think that a seemingly nicely working code should newly be littered with TODOs. That's not an improvement. If there is a problem, then it should be debugged and fixed.

@tautschnig tautschnig changed the title Make return type of set_l*_indices be a renamedt Make return type of set_l*_indices be a renamedt [blocks: #4333] Mar 6, 2019
@romainbrenguier romainbrenguier force-pushed the refactor/symex-rename branch from d723b64 to 5162021 Compare March 6, 2019 09:50
@romainbrenguier
Copy link
Contributor Author

@tautschnig I squashed three commits, the order looks fine for me now. I removed the TODOs since it seems there is nothing wrong there.

@romainbrenguier romainbrenguier removed their assignment Mar 6, 2019
Copy link
Collaborator

@tautschnig tautschnig left a comment

Choose a reason for hiding this comment

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

Certainly adds clarity, but I think we can reduce the size of the change quite a bit as indicated below. And some parts are still unclear to me.

set_l0_indices(ssa, ns);
{
const renamedt<ssa_exprt, L0> ssa_l0 = set_l0_indices(std::move(ssa), ns);
ssa = ssa_l0.get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does the temporary really add value? I think it's pretty clear what set_l0_indices does. Therefore I'd prefer ssa = set_l0_indices(std::move(ssa), ns).get();

set_l1_indices(ssa, ns);
{
const renamedt<ssa_exprt, L1> ssa_l1 = set_l1_indices(std::move(ssa), ns);
ssa = ssa_l1.get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Like for the level-0 case, I'd prefer ssa = set_l1_indices(std::move(ssa), ns).get();

@@ -312,7 +308,8 @@ exprt goto_symex_statet::rename(exprt expr, const namespacet &ns)
}
else if(level==L2)
{
set_l1_indices(ssa, ns);
const renamedt<ssa_exprt, L1> ssa_l1 = set_l1_indices(std::move(ssa), ns);
ssa = ssa_l1.get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

As above, ssa_l1 is not necessary.

set_l1_indices(ssa, ns);

const renamedt<ssa_exprt, L1> ssa_l1 = set_l1_indices(std::move(ssa), ns);
ssa = ssa_l1.get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

As above.

if(!l0_expr.get().get_level_1().empty())
if(
!l0_expr.get().get_level_1().empty() ||
!l0_expr.get().get_level_2().empty())
Copy link
Collaborator

Choose a reason for hiding this comment

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

To make sure there is no change in behaviour this will require an INVARIANT that !l0_expr.get().get_level_2().empty() implies !l0_expr.get().get_level_1().empty(). And I'm not convinced that holds, because a global variable would not need L1 renaming, even when L2 is non-empty.

Copy link
Contributor Author

@romainbrenguier romainbrenguier Mar 6, 2019

Choose a reason for hiding this comment

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

Yes this does not hold, so we can't add an invariant. The reason this does not change the behaviour is that it is only called from set_l1_indices which had the same check until this commit.


to_ssa_expr(tmp.false_case()).set_level_2(a_s_read.first);
if_exprt tmp{cond.as_expr(), l2_true_case.get(), l2_false_case.get()};
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we can delay the construction even further and just use l2_true_case, l2_false_case in the branches below? Overall your changes here indeed make the code much nicer!

expr=ssa_l1;
const renamedt<ssa_exprt, L2> ssa_l2 =
set_l2_indices(std::move(ssa_l1), ns);
expr = ssa_l2.get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

As above: get rid of ssa_l2.

expr=ssa_l1;
const renamedt<ssa_exprt, L2> ssa_l2 =
set_l2_indices(std::move(ssa_l1), ns);
expr = ssa_l2.get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

No need for ssa_l2.

set_l2_indices(ssa_l1, ns);
expr=ssa_l1;
const renamedt<ssa_exprt, L2> ssa_l2 = set_l2_indices(std::move(ssa_l1), ns);
expr = ssa_l2.get();
Copy link
Collaborator

Choose a reason for hiding this comment

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

As above.

@@ -67,6 +67,8 @@ operator()(renamedt<ssa_exprt, L0> l0_expr) const
renamedt<ssa_exprt, L2> symex_level2t::
operator()(renamedt<ssa_exprt, L1> l1_expr) const
{
if(!l1_expr.get().get_level_2().empty())
return renamedt<ssa_exprt, L2>{std::move(l1_expr.value)};
Copy link
Collaborator

Choose a reason for hiding this comment

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

This change seems surprising to me, but I'm likely just missing something. Would you mind explaining?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As for the symex_level1t case, it does not change the behaviour because it is only called from set_l2_indices which had the same check until this commit. We need the check to be here and not in set_l2_indices, because set_l2_indices cannot create renamedt expression, the constructor is private, this ensures we cannot make a renamedt without checking it has the right indices set.

This makes explicit that the result is a renamed expression and can be
propagated in through other functions.
This carries the information about which renaming the expression has
been through.
This requires a change in symex_level1t::operator() so that it takes
care of the non-empty level 2 case.
@romainbrenguier romainbrenguier force-pushed the refactor/symex-rename branch from 5162021 to c91db70 Compare March 6, 2019 11:56
This captures the information of which renaming the expression has been
through.

This requires making symex_level2t::operator() handle non-empty L2. This
was handled by set_l2_indices, but it is neccessary to handle it in
symex_level2t for making set_l2_indices return a renamedt.
@romainbrenguier romainbrenguier force-pushed the refactor/symex-rename branch from c91db70 to 1bb05b6 Compare March 6, 2019 12:01
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: 1bb05b6).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/103359871
Status will be re-evaluated on next push.
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 compatibility was already broken by an earlier merge.

@romainbrenguier romainbrenguier merged commit 00f125f into diffblue:develop Mar 6, 2019
@romainbrenguier romainbrenguier deleted the refactor/symex-rename branch March 6, 2019 13:11
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.

6 participants