Skip to content

Equivalent expressions: assignments [3/n] #802

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
merged 62 commits into from
Apr 6, 2020
Merged

Conversation

kkjeer
Copy link
Contributor

@kkjeer kkjeer commented Mar 4, 2020

This PR updates the sets UEQ and G of equivalent expressions while checking expressions that involve assignments. This is done with the following changes:

  • Update UEQ and G from CheckVarDecl (for declarations with initializers), CheckBinaryOperator (for assignments and compound assignments), and CheckUnaryOperator (for increment/decrement operators).
  • Add a GetIncomingBlockState method that gets the state that is true at the beginning of a CFG block by getting the intersection of the UEQ sets of the block's predecessors.
  • Add an UpdateAfterAssignment method that updates UEQ and G after an assignment to a variable V.
  • Add a GetOriginalValue method that gets the original value of a variable in an expression. Helper methods IsInvertible and Inverse are used to get the original value.
  • Add helpers PruneVariableReferences and VariableOccurrenceCount to help with getting the inverse of an expression.
  • Add utility classes VariableUtil and ExprCreatorUtil to help with detecting and comparing variables and creating certain kinds of expressions.
  • Modify asserts and diagnostic behavior in CanonBounds, TreeTransform, and SemaExpr to reflect the greater variety of expressions that can be lexicographically compared and transformed.

Testing:

  • Changed the behavior of the -fdump-checking-state flag to only dump the checking state after checking a top-level CFG statement, rather than after every expression. The equiv-exprs.c test has been modified to reflect this change.
  • Added a test equiv-expr-sets.c to test that the set UEQ of sets of equivalent expressions is properly updated while checking assignments. This file also tests that the incoming UEQ set is properly determined for CFG blocks in functions with if statements.
  • Passed manual testing on Windows.
  • Passed automated testing on Windows/Linux.

kakje added 30 commits February 26, 2020 18:19
Copy link
Member

@dtarditi dtarditi left a comment

Choose a reason for hiding this comment

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

I have suggestions for comment improvements and some issues to address in follow-up pull requests.

// Create the RHS of the implied assignment `e1 = e1 @ e2`.
Src = ExprCreatorUtil::CreateBinaryOperator(S, Target, RHS, Op);

// Update the set of expressions that produce the same value as `e1`.
Copy link
Member

Choose a reason for hiding this comment

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

I think this comment could be clarified to explain why we are doing this. Given that the compound assignment modifies e1, we need to choose an expression equal to the value of e1 before the assignment.

SubExprGs[Src] = State.G;
}

// Update UEQ and G for assignments to a variable `e1`.
Copy link
Member

Choose a reason for hiding this comment

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

In the comment, I think you should change variable to expression.

// Update State.G using the the target of the inc/dec operator for
// expressions where the integer constant 1 could not be constructed
// (e.g. floating point expressions). State.UEQ remains unchanged.
if (CheckIsNonModifying(Target) && CanBeInEqualExprSet(Target))
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't seem right. What if the expression is a pre-increment expression, such as ++e1? Target is not the correct value of the entire expression ++e1. I think in case where the increment/decrement literal does not have an integer type, it is fine to set G to the empty set.

@@ -3238,6 +3520,71 @@ namespace {
RValueBounds = Check(E, CSS, State);
}

// Methods to update sets of equivalent expressions.
Copy link
Member

Choose a reason for hiding this comment

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

The indentation is off.

return EqualValue(S.Context, V, Var, nullptr);
}

// CanBeInEqualExprSet returns true if the expression e can be added to
Copy link
Member

Choose a reason for hiding this comment

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

I think this method name is confusing. It should either be more descriptive, or also exclude non-modifying expressions.

@@ -2327,8 +2518,50 @@ namespace {
}
}

// Update State.UEQ and State.G.
Copy link
Member

Choose a reason for hiding this comment

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

I didn't see this comment addressed in your most recent change. It would have been helpful to have a clarifying response here about why it wasn't addressed.

I looked into this and see that UpdateG is screening out non-modifying expressions in the S_i. I am pretty concerned about this. Expression equivalence checking assumes that expressions are non-modifying expressions and may produce incorrect results if they are modifying expressions.

For this reason, I think we should have an invariant that none of the subexpressions G_i containy modifying expression. This change is already large and I'd rather land it now, then have it continune onward. @kkjeer could you file an issue about this, and follow-up in a subsequent check-in.

// BinaryOperator: compound assignment to a variable
void f3(unsigned i) {
// Updated UEQ: { { (i - 2) + 2, i } }
i += 2;
Copy link
Member

@dtarditi dtarditi Apr 2, 2020

Choose a reason for hiding this comment

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

This equality implied by the UEQ set is a tautology. (i-2)+2 is equivalent to i (ignoring overflow). So we are saying i == i. When updating UEQ information, we should screen out equality facts implied by assignments to variables where the variable also appears on the right-hand side of the assignments. It's fine to flag this as a follow-up issue. This is already a large pull request.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I created issue #814 to track this work.

Copy link
Member

@dtarditi dtarditi left a comment

Choose a reason for hiding this comment

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

Overall, looks great.

I have one last change regarding pre/post-increment expressions. We are trying to compute the non-modifying expression that is equivalent to the value produced by the pre/post-increment expression in the program state after the pre/post-increment expression has executed. The logic that you have reversed. In the state after executing ++x, x produces a value equivalent to the value produced by ++x.


// Update the set G of expressions that produce the same value as e.
if (RHS) {
// For post-inc/dec operators, use the rvalue for `e1` to update G.
Copy link
Member

Choose a reason for hiding this comment

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

This logic is reversed. In the state after the expression ++x has executed, the non-modifying expression equivalent to the value produced by ++x is x. For x++, the non-modifying expression is x - 1..

Copy link
Member

@dtarditi dtarditi left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you for the effort that you put into this change!

@kkjeer kkjeer merged commit cfefa2d into master Apr 6, 2020
@kkjeer kkjeer deleted the equiv-exprs-assignments branch April 11, 2020 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants