Skip to content
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

Handle discriminant in DataflowConstProp #107411

Merged
merged 8 commits into from
Feb 15, 2023

Conversation

cjgillot
Copy link
Contributor

cc @jachris
r? @JakobDegen

This PR attempts to extend the DataflowConstProp pass to handle propagation of discriminants. We handle this by adding 2 new variants to TrackElem: TrackElem::Variant for enum variants and TrackElem::Discriminant for the enum discriminant pseudo-place.

The difficulty is that the enum discriminant and enum variants may alias each another. This is the issue of the Option<NonZeroUsize> test, which is the equivalent of rust-lang/unsafe-code-guidelines#84 with a direct write.

To handle that, we generalize the flood process to flood all the potentially aliasing places. In particular:

  • any write to (PLACE as Variant), either direct or through a projection, floods (PLACE as OtherVariant) for all other variants and discriminant(PLACE);
  • SetDiscriminant(PLACE) floods (PLACE as Variant) for each variant.

This implies that flooding is not hierarchical any more, and that an assignment to a non-tracked place may need to flood a tracked place. This is handled by for_each_aliasing_place which generalizes preorder_invoke.

As we deaggregate enums by putting SetDiscriminant last, this allows to propagate the value of the discriminant.

This refactor will allow to make #107009 able to handle discriminants too.

@rustbot
Copy link
Collaborator

rustbot commented Jan 28, 2023

Failed to set assignee to JakobDegen: invalid assignee

Note: Only org members, users with write permissions, or people who have commented on the PR may be assigned.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 28, 2023
@rustbot
Copy link
Collaborator

rustbot commented Jan 28, 2023

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

@cjgillot
Copy link
Contributor Author

r? wg-mir-opt

Copy link
Contributor

@jachris jachris left a comment

Choose a reason for hiding this comment

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

Nice! Great to have propagation of discriminants and through downcasts back again. It seems to me like this here should be sound. And limiting the tracking when creating the map is a much better fallback than what we currently have.

There is now quite some duplication due to all the _discr methods, perhaps there is a nice way to unify this.

compiler/rustc_mir_dataflow/src/value_analysis.rs Outdated Show resolved Hide resolved
}
}

/// The target place must have been flooded before calling this method.
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 the behavior of find followed by assign_idx should be the same as assign. But flooding now requires the actual place instead of just its index, so... Perhaps the easier way is to just rename assign_idx to reflect the different behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you have a suggestion for the name? I'm a bit out of inspiration.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe something like assign_idx_without_flood. I think a long name is fine, as this is also a dangerous function to call. This also makes it obvious that DataflowConstProp has to flood before using this method when handling the checked binary operator.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can also consider renaming assign_place_idx.

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 renamed them insert_*_idx.
About dangerousness: #107009 interprets MIR backwards, so it needs to call these functions before flooding.

@bors
Copy link
Contributor

bors commented Jan 29, 2023

☔ The latest upstream changes (presumably #106908) made this pull request unmergeable. Please resolve the merge conflicts.

@bors
Copy link
Contributor

bors commented Feb 2, 2023

☔ The latest upstream changes (presumably #107601) made this pull request unmergeable. Please resolve the merge conflicts.

@bors
Copy link
Contributor

bors commented Feb 4, 2023

☔ The latest upstream changes (presumably #107267) made this pull request unmergeable. Please resolve the merge conflicts.

@oli-obk
Copy link
Contributor

oli-obk commented Feb 4, 2023

Most of this PR should now be unnecessary now that we don't deaggregate anymore, right?

@cjgillot
Copy link
Contributor Author

cjgillot commented Feb 5, 2023

This PR has 2 parts:

  1. an extension of the flood model to correctly discard aliasing projections when assigning to a variant;
  2. the handling of discriminants and variants in the pass.

We do not ban direct assignment to variants, see the mutate_discriminant test case. As we do not deaggregate, those direct assignments do not "naturally" appear in MIR any more (except for generators, that this pass does not handle), but may be introduced by other passes.

Remains the question of the semantics of

a = NonZeroUsize { 0: 0_usize }
b = Option::<NonZeroUsize>::Some(a)

Notably:

  • under the current implementation of interpret and codegen, discriminant assignment comes last, so discriminant(b) is 1;
  • but what is (b as Some).0.0? ConstProp and codegen would say 1, this pass must decide on 0 or 1.

There are 2 ways to handle this:
a. this PR;
b. we ban direct assignment to enum variants, with a check in MIR validation (keeping such assignements for generators).

(b) renders part (1) of this PR unnecessary, as all such assignments will go through pointers, unsupported by this pass. I would also remove the TrackElem::Variant, as those would be systematically flooded by the aggregate assignment.

@bors
Copy link
Contributor

bors commented Feb 6, 2023

☔ The latest upstream changes (presumably #107727) made this pull request unmergeable. Please resolve the merge conflicts.

Copy link
Contributor

@oli-obk oli-obk left a comment

Choose a reason for hiding this comment

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

r=me with typo fixed

compiler/rustc_mir_transform/src/dataflow_const_prop.rs Outdated Show resolved Hide resolved
@oli-obk
Copy link
Contributor

oli-obk commented Feb 13, 2023

@bors r+

@bors
Copy link
Contributor

bors commented Feb 13, 2023

📌 Commit 09797a4 has been approved by oli-obk

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 13, 2023
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Feb 14, 2023
…oli-obk

Handle discriminant in DataflowConstProp

cc `@jachris`
r? `@JakobDegen`

This PR attempts to extend the DataflowConstProp pass to handle propagation of discriminants. We handle this by adding 2 new variants to `TrackElem`: `TrackElem::Variant` for enum variants and `TrackElem::Discriminant` for the enum discriminant pseudo-place.

The difficulty is that the enum discriminant and enum variants may alias each another. This is the issue of the `Option<NonZeroUsize>` test, which is the equivalent of rust-lang/unsafe-code-guidelines#84 with a direct write.

To handle that, we generalize the flood process to flood all the potentially aliasing places. In particular:
- any write to `(PLACE as Variant)`, either direct or through a projection, floods `(PLACE as OtherVariant)` for all other variants and `discriminant(PLACE)`;
- `SetDiscriminant(PLACE)` floods `(PLACE as Variant)` for each variant.

This implies that flooding is not hierarchical any more, and that an assignment to a non-tracked place may need to flood a tracked place. This is handled by `for_each_aliasing_place` which generalizes `preorder_invoke`.

As we deaggregate enums by putting `SetDiscriminant` last, this allows to propagate the value of the discriminant.

This refactor will allow to make rust-lang#107009 able to handle discriminants too.
bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 15, 2023
Rollup of 7 pull requests

Successful merges:

 - rust-lang#105300 (rework min_choice algorithm of member constraints)
 - rust-lang#107163 (Remove some superfluous type parameters from layout.rs.)
 - rust-lang#107173 (Suggest the correct array length on mismatch)
 - rust-lang#107411 (Handle discriminant in DataflowConstProp)
 - rust-lang#107968 (Enable `#[thread_local]` on armv6k-nintendo-3ds)
 - rust-lang#108032 (Un📦ing the Resolver)
 - rust-lang#108060 (Revert to using `RtlGenRandom` as a fallback)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit c78e3c7 into rust-lang:master Feb 15, 2023
@rustbot rustbot added this to the 1.69.0 milestone Feb 15, 2023
@cjgillot cjgillot deleted the dataflow-discriminant branch February 15, 2023 18:32
compiler-errors added a commit to compiler-errors/rust that referenced this pull request Feb 21, 2023
Correctly handle aggregates in DataflowConstProp

The previous implementation from rust-lang#107411 flooded target of an aggregate assignment with `Bottom`, corresponding to the `deinit` that the interpreter does.

As a consequence, when assigning `target = Enum::Variant#i(...)` all the `(target as Variant#j)` were at `Bottom` while they should have been `Top`.

This PR replaces that flooding with `Top`.

Aside, it corrects a second bug where the wrong place would be used to assign to enum variant fields, resulting to nothing happening.

Fixes rust-lang#108166
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 23, 2023
Correctly handle aggregates in DataflowConstProp

The previous implementation from rust-lang#107411 flooded target of an aggregate assignment with `Bottom`, corresponding to the `deinit` that the interpreter does.

As a consequence, when assigning `target = Enum::Variant#i(...)` all the `(target as Variant#j)` were at `Bottom` while they should have been `Top`.

This PR replaces that flooding with `Top`.

Aside, it corrects a second bug where the wrong place would be used to assign to enum variant fields, resulting to nothing happening.

Fixes rust-lang#108166
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants