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

Fixes to mir dataflow #33667

Merged
merged 48 commits into from
May 25, 2016
Merged

Fixes to mir dataflow #33667

merged 48 commits into from
May 25, 2016

Conversation

pnkfelix
Copy link
Member

@pnkfelix pnkfelix commented May 16, 2016

Fixes to mir dataflow

This collects a bunch of changes to rustc_borrowck::borrowck::dataflow (which others have pointed out should probably migrate to some crate that isn't tied to the borrow-checker -- but I have not attempted that here, especially since there are competing approaches to dataflow that we should also evaluate).

These changes:

  1. Provide a family of related analyses: MovingOutStatements (which is what the old AST-based dataflo computed), as well as MaybeInitialized, MaybeUninitalized, and DefinitelyInitialized.
    • (The last two are actually inverses of each other; we should pick one and drop the other.)
  2. Fix bugs in the pre-existing analysis implementation, which was untested and thus some obvious bugs went unnoticed, which brings us to the third point:
  3. Add a unit test infrastructure for the MIR dataflow analysis.
    • The tests work by adding a new intrinsic that is able to query the analysis state for a particular expression (technically, a particular L-value).
    • See the examples in compile-fail/mir-dataflow/inits-1.rs and compile-fail/mir-dataflow/uninits-1.rs
    • These tests are only checking the results for MaybeInitialized, MaybeUninitalized, and DefinitelyInitialized; I am not sure if it will be feasible to generalize this testing strategy to the MovingOutStatements dataflow operator.

(bug was cut/pasted into `rustc_borrowck::bitslice`, so I fixed it
there as well.)
…outines.

(The crucial thing these changes are working toward (but are not yet
in this commit) is a way to pretty-print MIR without having the
`NodeId` for that MIR in hand.)
…nreferenced.

includes misc bug fixes and removal of useless code.
Incorporates many fixes contributed by arielb1.

----

revise borrowck::mir::dataflow code to allow varying domain for bitvectors.

This particular code implements the `BitDenotation` trait for three
analyses:

 * `MovingOutStatements`, which, like `borrowck::move_data`, maps each
   bit-index to a move instruction, and a 1 means "the effect of this
   move reaches this point" (and the assigned l-value, if a scoped
   declaration, is still in scope).

 * `MaybeInitializedLvals`, which maps each bit-index to an l-value.
   A 1 means "there exists a control flow path to this point that
   initializes the associated l-value."

 * `MaybeUninitializedLvals`, which maps each bit-index to an l-value
   A 1 means "there exists a control flow path to this point that
   de-initializes the associated l-value."

----

Revised `graphviz` dataflow-rendering support in `borrowck::mir`.

One big difference is that this code is now parameterized over the
`BitDenotation`, so that it can be used to render dataflow results
independent of how the dataflow bitvectors are interpreted; see where
reference to `MoveOut` is replaced by the type parameter `D`.

----

Factor out routine to query subattributes in `#[rustc_mir(..)]`.

(Later commits build upon this for some unit testing and instrumentation.)

----

thread through a tcx so that I can query types of lvalues as part of analysis.

----

Revised `BitDenotation::Ctxt`, allowing variation beyond `MoveData`.

The main motivation is to ease threading through a `TyCtxt`.

(In hindsight it might have been better to instead attach the `TyCtxt`
to each of the different dataflow implementations, but that would
require e.g. switching away from having a `Default` impl, so I am
leaving that experiment for another time.)
its own needs based on attributes attached to the function where it
appears.
(The static semantics of `rustc_peek` is derived from attributes
attached to the function being compiled; in this case,
`rustc_peek(&expr)` observes the dataflow state for the l-value
`expr`.)
These use new `rustc_peek` (whose semantics is driven by attribute
attached to fn).
@rust-highfive
Copy link
Collaborator

r? @Aatch

(rust_highfive has picked a reviewer for you, use r? to override)

@pnkfelix
Copy link
Member Author

r? @nikomatsakis

cc @arielb1

/// attached to the function.
///
/// For example, dataflow uses this to inject static assertions so
/// that `rustc_oeek(potentially_uninitialized)` would actually
Copy link
Member

Choose a reason for hiding this comment

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

Typo: oeek.

// it will always appear like Lvalues are initialized; e.g. in
// a case like:
//
// <bitset maps var1 to 0>
Copy link
Contributor

Choose a reason for hiding this comment

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

What is this talking about? rustc_peek(&var1) should be translated to

        tmp1 = &var0;
        tmp0 = rustc_peek(tmp1) -> bb1;

If it copies the lvalue before taking a reference, that would be totally broken (consider Cell). So it doesn't. Unless something funny is going on here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh you're right; I didn't update that comment correctly (it was originally authored for a different version of rustc_peek that looked like rustc_peek(var1) (instead of rustc_peek(&var1)), and I erroneously translated its content without thinking about what the actual translation of rustc_peek(&var1) is).

(The original version of rustc_peek had a more fragile API, where one would write rustc_peek(expr) (instead of rustc_peek(&expr)).)


The main point I'm trying to make is this: even with the corrected translation that you wrote:

tmp1 = &var0;
tmp0 = rustc_peek(tmp1) -> bb1;

The normal (naive) dataflow GEN/KILL sets are going to say that tmp1 is initialized. If the semantics of rustc_peek were a naive "look directly at your argument's dataflow bit state", then rustc_peek would query the state of tmp1, which would always indicate that it has been initialized under the naive rules.

So I had written a comment about a work-around I was using for the naive system.


With the new API the story is somewhat related, but the example I gave in the comment isn't helping explain things.

I will update it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guessed. Yeah, you want the state of var0, not of tmp1. I think you could just go to the initialization of tmp1 and use that.

Copy link
Contributor

Choose a reason for hiding this comment

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

(I also expected to find the definition of tmp1 when @pnkfelix and I discussed in the work week; but this solution works too.)

Copy link
Contributor

@nikomatsakis nikomatsakis May 17, 2016

Choose a reason for hiding this comment

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

I guess the reason not to do rustc_peek(&x) is that this code runs before borrowck anyway, so e.g. moves don't matter? never mind, I see you are doing &x

@nikomatsakis
Copy link
Contributor

I gave this a brief review and it seems quite reasonable. I'll try to read a bit more in detail tomorrow though.

… presentation.

As a drive-by: unified pair of match arms that flowed to `bug!`, and
replaced `bug!` invocation with a diagnostic `span_err` invocation.
Also got rid of the `trait HasMoveData`, since I am now just imposing
the constraint that `BitDenotation<Ctxt=MoveData<'tcx>>` where
necessary instead.
… associated Ctxt item.

used this to address a long-standing wart/bug in how filtering-out of
values with type impl'ing `Copy` was done.
@pnkfelix
Copy link
Member Author

pnkfelix commented May 24, 2016

@arielb1 @nikomatsakis The one thing I'd like someone to take a look at is the new indexed_set abstraction that I am using as a layer atop bitvectors.

My goal was to have a breakdown analogous to Vec<T>/[T] (namely, one is owned, and the other is unsized and can be used with either &[T] or &mut [T]).

My analogous types in indexed_set are OwnIdxSet<T> and IdxSet<T>, where in both cases the phantom type parameter T must implement the trait Idx (also introduced in this module), since the T must be able to be mapped to a usize for the subsequent indexing into the bitvector.

My problem is that I used a little bit of nasty unsafe code to accomplish this goal. :( (Namely, I did not see a way to turn a &[usize] slice reference into a &IdxSet<T> besides using transmute.)


Maybe the right answer here is to not attempt to provide an unsized IdxSet<T> type, but instead to provide RefIdxSet<'a, T> and MutIdxSet<'a, T>. I briefly considered this but for some reason my initial drafts seemed really unappealing. Still, if either of you wants to insist that this be composed of 100% safe code, I can go back in and do that replacement.

/// "transfer-function" represnting the overall-effect of the
/// block, represented via GEN and KILL sets.
///
/// The statement here is `idx_stmt.1`; `idx_stmt.0` is just
Copy link
Member Author

Choose a reason for hiding this comment

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

(note to self: this, like many comments, is out of date and needs to be fixed to reflect changes to the API here.)

// requires a transmute relying on representation guarantees that may
// not hold in the future.

pub struct IdxSet<T: Idx> {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd have appreciated a comment explaining what T is.

@nikomatsakis
Copy link
Contributor

My feeling is that we should land this PR -- it seems like it contains many clear improvements and bug fixes, and it's big enough that we could keep iterating forever with nitpicks. I'd rather land it and then address further problems in follow-up PRs. @arielb1 -- thoughts?

@arielb1
Copy link
Contributor

arielb1 commented May 25, 2016

I'll go for that

@bors r+

@bors
Copy link
Contributor

bors commented May 25, 2016

📌 Commit df5c116 has been approved by arielb1

@bors
Copy link
Contributor

bors commented May 25, 2016

⌛ Testing commit df5c116 with merge 34fd686...

bors added a commit that referenced this pull request May 25, 2016
Fixes to mir dataflow

Fixes to mir dataflow

This collects a bunch of changes to `rustc_borrowck::borrowck::dataflow` (which others have pointed out should probably migrate to some crate that isn't tied to the borrow-checker -- but I have not attempted that here, especially since there are competing approaches to dataflow that we should also evaluate).

These changes:
 1. Provide a family of related analyses: MovingOutStatements (which is what the old AST-based dataflo computed), as well as MaybeInitialized, MaybeUninitalized, and DefinitelyInitialized.
   * (The last two are actually inverses of each other; we should pick one and drop the other.)
 2. Fix bugs in the pre-existing analysis implementation, which was untested and thus some obvious bugs went unnoticed, which brings us to the third point:
 3. Add a unit test infrastructure for the MIR dataflow analysis.
   * The tests work by adding a new intrinsic that is able to query the analysis state for a particular expression (technically, a particular L-value).
   * See the examples in compile-fail/mir-dataflow/inits-1.rs and compile-fail/mir-dataflow/uninits-1.rs
   * These tests are only checking the results for MaybeInitialized, MaybeUninitalized, and DefinitelyInitialized; I am not sure if it will be feasible to generalize this testing strategy to the MovingOutStatements dataflow operator.
@bors bors merged commit df5c116 into rust-lang:master May 25, 2016
@nikomatsakis
Copy link
Contributor

Yay!
On May 25, 2016 6:38 PM, "bors" notifications@github.com wrote:

☀️ Test successful - auto-linux-32-nopt-t
http://buildbot.rust-lang.org/builders/auto-linux-32-nopt-t/builds/9268,
auto-linux-32-opt
http://buildbot.rust-lang.org/builders/auto-linux-32-opt/builds/9305,
auto-linux-32cross-opt
http://buildbot.rust-lang.org/builders/auto-linux-32cross-opt/builds/388,
auto-linux-64-cargotest
http://buildbot.rust-lang.org/builders/auto-linux-64-cargotest/builds/580,
auto-linux-64-cross-armhf
http://buildbot.rust-lang.org/builders/auto-linux-64-cross-armhf/builds/391,
auto-linux-64-cross-armsf
http://buildbot.rust-lang.org/builders/auto-linux-64-cross-armsf/builds/395,
auto-linux-64-cross-freebsd
http://buildbot.rust-lang.org/builders/auto-linux-64-cross-freebsd/builds/394,
auto-linux-64-cross-netbsd
http://buildbot.rust-lang.org/builders/auto-linux-64-cross-netbsd/builds/394,
auto-linux-64-debug-opt
http://buildbot.rust-lang.org/builders/auto-linux-64-debug-opt/builds/2536,
auto-linux-64-nopt-t
http://buildbot.rust-lang.org/builders/auto-linux-64-nopt-t/builds/9243,
auto-linux-64-opt
http://buildbot.rust-lang.org/builders/auto-linux-64-opt/builds/9229,
auto-linux-64-opt-mir
http://buildbot.rust-lang.org/builders/auto-linux-64-opt-mir/builds/815,
auto-linux-64-opt-rustbuild
http://buildbot.rust-lang.org/builders/auto-linux-64-opt-rustbuild/builds/1200,
auto-linux-64-x-android-t
http://buildbot.rust-lang.org/builders/auto-linux-64-x-android-t/builds/9225,
auto-linux-cross-opt
http://buildbot.rust-lang.org/builders/auto-linux-cross-opt/builds/2436,
auto-linux-musl-64-opt
http://buildbot.rust-lang.org/builders/auto-linux-musl-64-opt/builds/4380,
auto-mac-32-opt
http://buildbot.rust-lang.org/builders/auto-mac-32-opt/builds/9285,
auto-mac-64-nopt-t
http://buildbot.rust-lang.org/builders/auto-mac-64-nopt-t/builds/9290,
auto-mac-64-opt
http://buildbot.rust-lang.org/builders/auto-mac-64-opt/builds/9255,
auto-mac-64-opt-rustbuild
http://buildbot.rust-lang.org/builders/auto-mac-64-opt-rustbuild/builds/1209,
auto-mac-cross-ios-opt
http://buildbot.rust-lang.org/builders/auto-mac-cross-ios-opt/builds/393,
auto-win-gnu-32-nopt-t
http://buildbot.rust-lang.org/builders/auto-win-gnu-32-nopt-t/builds/4323,
auto-win-gnu-32-opt
http://buildbot.rust-lang.org/builders/auto-win-gnu-32-opt/builds/4330,
auto-win-gnu-32-opt-rustbuild
http://buildbot.rust-lang.org/builders/auto-win-gnu-32-opt-rustbuild/builds/1218,
auto-win-gnu-64-nopt-t
http://buildbot.rust-lang.org/builders/auto-win-gnu-64-nopt-t/builds/4323,
auto-win-gnu-64-opt
http://buildbot.rust-lang.org/builders/auto-win-gnu-64-opt/builds/4309,
auto-win-msvc-32-cross-opt
http://buildbot.rust-lang.org/builders/auto-win-msvc-32-cross-opt/builds/679,
auto-win-msvc-32-opt
http://buildbot.rust-lang.org/builders/auto-win-msvc-32-opt/builds/3530,
auto-win-msvc-64-cargotest
http://buildbot.rust-lang.org/builders/auto-win-msvc-64-cargotest/builds/583,
auto-win-msvc-64-opt
http://buildbot.rust-lang.org/builders/auto-win-msvc-64-opt/builds/4321,
auto-win-msvc-64-opt-mir
http://buildbot.rust-lang.org/builders/auto-win-msvc-64-opt-mir/builds/822,
auto-win-msvc-64-opt-rustbuild
http://buildbot.rust-lang.org/builders/auto-win-msvc-64-opt-rustbuild/builds/1217


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#33667 (comment)

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.

8 participants