2020-03-11 11:49:08 +00:00
|
|
|
|
use rustc::mir::traversal;
|
|
|
|
|
use rustc::mir::{self, BasicBlock, BasicBlockData, Body, Location, Statement, Terminator};
|
|
|
|
|
use rustc::ty::{self, TyCtxt};
|
2020-02-29 17:37:32 +00:00
|
|
|
|
use rustc_ast::ast::{self, MetaItem};
|
2020-01-11 16:02:46 +00:00
|
|
|
|
use rustc_ast_pretty::pprust;
|
2019-12-22 22:42:04 +00:00
|
|
|
|
use rustc_data_structures::work_queue::WorkQueue;
|
2020-03-11 11:49:08 +00:00
|
|
|
|
use rustc_hir::def_id::DefId;
|
2019-09-26 05:30:10 +00:00
|
|
|
|
use rustc_index::bit_set::{BitSet, HybridBitSet};
|
2019-09-26 05:38:33 +00:00
|
|
|
|
use rustc_index::vec::Idx;
|
2020-03-11 11:49:08 +00:00
|
|
|
|
use rustc_session::Session;
|
|
|
|
|
use rustc_span::symbol::{sym, Symbol};
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
|
2018-03-05 07:44:10 +00:00
|
|
|
|
use std::borrow::Borrow;
|
2017-11-24 12:00:09 +00:00
|
|
|
|
use std::fmt;
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
use std::io;
|
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
pub use self::at_location::{FlowAtLocation, FlowsAtLocation};
|
|
|
|
|
pub(crate) use self::drop_flag_effects::*;
|
|
|
|
|
pub use self::impls::borrows::Borrows;
|
2018-08-30 21:54:32 +00:00
|
|
|
|
pub use self::impls::DefinitelyInitializedPlaces;
|
2018-01-28 23:49:29 +00:00
|
|
|
|
pub use self::impls::EverInitializedPlaces;
|
2020-02-12 21:36:47 +00:00
|
|
|
|
pub use self::impls::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
|
2019-12-22 22:42:04 +00:00
|
|
|
|
pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
|
2020-02-18 18:35:16 +00:00
|
|
|
|
pub use self::impls::{MaybeRequiresStorage, MaybeStorageLive};
|
2017-06-26 12:57:26 +00:00
|
|
|
|
|
2017-07-04 10:38:48 +00:00
|
|
|
|
use self::move_paths::MoveData;
|
|
|
|
|
|
2017-12-07 15:00:26 +00:00
|
|
|
|
mod at_location;
|
2018-08-30 21:54:32 +00:00
|
|
|
|
pub mod drop_flag_effects;
|
2019-09-17 23:25:29 +00:00
|
|
|
|
pub mod generic;
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
mod graphviz;
|
2016-05-24 11:26:54 +00:00
|
|
|
|
mod impls;
|
2017-06-26 12:57:26 +00:00
|
|
|
|
pub mod move_paths;
|
|
|
|
|
|
2019-04-01 18:38:00 +00:00
|
|
|
|
pub(crate) mod indexes {
|
|
|
|
|
pub(crate) use super::{
|
|
|
|
|
impls::borrows::BorrowIndex,
|
2019-12-22 22:42:04 +00:00
|
|
|
|
move_paths::{InitIndex, MoveOutIndex, MovePathIndex},
|
2019-04-01 18:38:00 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
2017-06-26 12:57:26 +00:00
|
|
|
|
|
2019-06-14 16:39:39 +00:00
|
|
|
|
pub(crate) struct DataflowBuilder<'a, 'tcx, BD>
|
2018-12-17 16:26:24 +00:00
|
|
|
|
where
|
2019-06-16 09:41:24 +00:00
|
|
|
|
BD: BitDenotation<'tcx>,
|
2017-06-26 12:57:26 +00:00
|
|
|
|
{
|
2019-03-17 10:36:10 +00:00
|
|
|
|
def_id: DefId,
|
2017-06-26 12:57:26 +00:00
|
|
|
|
flow_state: DataflowAnalysis<'a, 'tcx, BD>,
|
|
|
|
|
print_preflow_to: Option<String>,
|
|
|
|
|
print_postflow_to: Option<String>,
|
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
|
2017-11-24 12:00:09 +00:00
|
|
|
|
/// `DebugFormatted` encapsulates the "{:?}" rendering of some
|
|
|
|
|
/// arbitrary value. This way: you pay cost of allocating an extra
|
|
|
|
|
/// string (as well as that of rendering up-front); in exchange, you
|
|
|
|
|
/// don't have to hand over ownership of your value or deal with
|
|
|
|
|
/// borrowing it.
|
2019-09-06 05:31:09 +00:00
|
|
|
|
pub struct DebugFormatted(String);
|
2017-11-24 12:00:09 +00:00
|
|
|
|
|
|
|
|
|
impl DebugFormatted {
|
2018-02-23 18:15:26 +00:00
|
|
|
|
pub fn new(input: &dyn fmt::Debug) -> DebugFormatted {
|
2017-11-24 12:00:09 +00:00
|
|
|
|
DebugFormatted(format!("{:?}", input))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Debug for DebugFormatted {
|
2019-02-07 21:28:15 +00:00
|
|
|
|
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2017-11-24 12:00:09 +00:00
|
|
|
|
write!(w, "{}", self.0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 05:31:09 +00:00
|
|
|
|
pub trait Dataflow<'tcx, BD: BitDenotation<'tcx>> {
|
2017-07-05 12:52:18 +00:00
|
|
|
|
/// Sets up and runs the dataflow problem, using `p` to render results if
|
|
|
|
|
/// implementation so chooses.
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn dataflow<P>(&mut self, p: P)
|
|
|
|
|
where
|
|
|
|
|
P: Fn(&BD, BD::Idx) -> DebugFormatted,
|
|
|
|
|
{
|
2017-07-05 12:52:18 +00:00
|
|
|
|
let _ = p; // default implementation does not instrument process.
|
|
|
|
|
self.build_sets();
|
|
|
|
|
self.propagate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets up the entry, gen, and kill sets for this instance of a dataflow problem.
|
|
|
|
|
fn build_sets(&mut self);
|
|
|
|
|
|
|
|
|
|
/// Finds a fixed-point solution to this instance of a dataflow problem.
|
|
|
|
|
fn propagate(&mut self);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-14 16:39:39 +00:00
|
|
|
|
impl<'a, 'tcx, BD> Dataflow<'tcx, BD> for DataflowBuilder<'a, 'tcx, BD>
|
2018-12-17 16:26:24 +00:00
|
|
|
|
where
|
2019-06-16 09:41:24 +00:00
|
|
|
|
BD: BitDenotation<'tcx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
{
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn dataflow<P>(&mut self, p: P)
|
|
|
|
|
where
|
|
|
|
|
P: Fn(&BD, BD::Idx) -> DebugFormatted,
|
|
|
|
|
{
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
self.flow_state.build_sets();
|
2019-12-22 22:42:04 +00:00
|
|
|
|
self.pre_dataflow_instrumentation(|c, i| p(c, i)).unwrap();
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
self.flow_state.propagate();
|
2019-12-22 22:42:04 +00:00
|
|
|
|
self.post_dataflow_instrumentation(|c, i| p(c, i)).unwrap();
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
2017-07-05 12:52:18 +00:00
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn build_sets(&mut self) {
|
|
|
|
|
self.flow_state.build_sets();
|
|
|
|
|
}
|
|
|
|
|
fn propagate(&mut self) {
|
|
|
|
|
self.flow_state.propagate();
|
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-08 03:21:18 +00:00
|
|
|
|
pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option<MetaItem> {
|
2017-07-04 10:38:48 +00:00
|
|
|
|
for attr in attrs {
|
2019-05-08 03:21:18 +00:00
|
|
|
|
if attr.check_name(sym::rustc_mir) {
|
2017-07-04 10:38:48 +00:00
|
|
|
|
let items = attr.meta_item_list();
|
|
|
|
|
for item in items.iter().flat_map(|l| l.iter()) {
|
|
|
|
|
match item.meta_item() {
|
|
|
|
|
Some(mi) if mi.check_name(name) => return Some(mi.clone()),
|
2019-12-22 22:42:04 +00:00
|
|
|
|
_ => continue,
|
2017-07-04 10:38:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 21:48:52 +00:00
|
|
|
|
pub struct MoveDataParamEnv<'tcx> {
|
2017-07-04 10:38:48 +00:00
|
|
|
|
pub(crate) move_data: MoveData<'tcx>,
|
2019-06-13 21:48:52 +00:00
|
|
|
|
pub(crate) param_env: ty::ParamEnv<'tcx>,
|
2017-07-04 10:38:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 05:31:09 +00:00
|
|
|
|
pub fn do_dataflow<'a, 'tcx, BD, P>(
|
2019-06-13 21:48:52 +00:00
|
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-11 21:11:55 +00:00
|
|
|
|
body: &'a Body<'tcx>,
|
|
|
|
|
def_id: DefId,
|
|
|
|
|
attributes: &[ast::Attribute],
|
|
|
|
|
dead_unwinds: &BitSet<BasicBlock>,
|
|
|
|
|
bd: BD,
|
|
|
|
|
p: P,
|
|
|
|
|
) -> DataflowResults<'tcx, BD>
|
|
|
|
|
where
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
BD: BitDenotation<'tcx>,
|
2019-06-11 21:11:55 +00:00
|
|
|
|
P: Fn(&BD, BD::Idx) -> DebugFormatted,
|
2017-07-04 10:38:48 +00:00
|
|
|
|
{
|
2019-06-03 22:26:48 +00:00
|
|
|
|
let flow_state = DataflowAnalysis::new(body, dead_unwinds, bd);
|
2019-03-17 10:36:10 +00:00
|
|
|
|
flow_state.run(tcx, def_id, attributes, p)
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-14 16:39:39 +00:00
|
|
|
|
impl<'a, 'tcx, BD> DataflowAnalysis<'a, 'tcx, BD>
|
2019-06-11 21:11:55 +00:00
|
|
|
|
where
|
|
|
|
|
BD: BitDenotation<'tcx>,
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
{
|
2019-06-11 21:11:55 +00:00
|
|
|
|
pub(crate) fn run<P>(
|
|
|
|
|
self,
|
2019-06-13 21:48:52 +00:00
|
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-11 21:11:55 +00:00
|
|
|
|
def_id: DefId,
|
|
|
|
|
attributes: &[ast::Attribute],
|
|
|
|
|
p: P,
|
|
|
|
|
) -> DataflowResults<'tcx, BD>
|
|
|
|
|
where
|
|
|
|
|
P: Fn(&BD, BD::Idx) -> DebugFormatted,
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
{
|
|
|
|
|
let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option<String> {
|
|
|
|
|
if let Some(item) = has_rustc_mir_with(attrs, name) {
|
|
|
|
|
if let Some(s) = item.value_str() {
|
2019-12-22 22:42:04 +00:00
|
|
|
|
return Some(s.to_string());
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
} else {
|
2019-10-08 20:17:46 +00:00
|
|
|
|
let path = pprust::path_to_string(&item.path);
|
|
|
|
|
sess.span_err(item.span, &format!("{} attribute requires a path", path));
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
return None;
|
|
|
|
|
}
|
2017-07-04 10:38:48 +00:00
|
|
|
|
}
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
return None;
|
|
|
|
|
};
|
2017-07-04 10:38:48 +00:00
|
|
|
|
|
2019-05-08 03:21:18 +00:00
|
|
|
|
let print_preflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_preflow);
|
|
|
|
|
let print_postflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_postflow);
|
2017-07-04 10:38:48 +00:00
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
let mut mbcx =
|
|
|
|
|
DataflowBuilder { def_id, print_preflow_to, print_postflow_to, flow_state: self };
|
2017-07-04 10:38:48 +00:00
|
|
|
|
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
mbcx.dataflow(p);
|
|
|
|
|
mbcx.flow_state.results()
|
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-16 09:41:24 +00:00
|
|
|
|
struct PropagationContext<'b, 'a, 'tcx, O>
|
|
|
|
|
where
|
2019-06-22 16:13:19 +00:00
|
|
|
|
O: BitDenotation<'tcx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
{
|
|
|
|
|
builder: &'b mut DataflowAnalysis<'a, 'tcx, O>,
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-16 09:41:24 +00:00
|
|
|
|
impl<'a, 'tcx, BD> DataflowAnalysis<'a, 'tcx, BD>
|
|
|
|
|
where
|
|
|
|
|
BD: BitDenotation<'tcx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
{
|
|
|
|
|
fn propagate(&mut self) {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
let mut temp = BitSet::new_empty(self.flow_state.sets.bits_per_block);
|
2019-12-22 22:42:04 +00:00
|
|
|
|
let mut propcx = PropagationContext { builder: self };
|
2018-07-02 18:48:54 +00:00
|
|
|
|
propcx.walk_cfg(&mut temp);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_sets(&mut self) {
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
// Build the transfer function for each block.
|
2019-06-03 22:26:48 +00:00
|
|
|
|
for (bb, data) in self.body.basic_blocks().iter_enumerated() {
|
2016-09-19 20:50:00 +00:00
|
|
|
|
let &mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = data;
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
let trans = self.flow_state.sets.trans_mut_for(bb.index());
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
for j_stmt in 0..statements.len() {
|
2017-07-03 15:58:19 +00:00
|
|
|
|
let location = Location { block: bb, statement_index: j_stmt };
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
self.flow_state.operator.before_statement_effect(trans, location);
|
|
|
|
|
self.flow_state.operator.statement_effect(trans, location);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if terminator.is_some() {
|
2017-07-03 15:58:19 +00:00
|
|
|
|
let location = Location { block: bb, statement_index: statements.len() };
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
self.flow_state.operator.before_terminator_effect(trans, location);
|
|
|
|
|
self.flow_state.operator.terminator_effect(trans, location);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
|
|
|
|
|
// Initialize the flow state at entry to the start block.
|
|
|
|
|
let on_entry = self.flow_state.sets.entry_set_mut_for(mir::START_BLOCK.index());
|
|
|
|
|
self.flow_state.operator.start_block_effect(on_entry);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-16 09:41:24 +00:00
|
|
|
|
impl<'b, 'a, 'tcx, BD> PropagationContext<'b, 'a, 'tcx, BD>
|
|
|
|
|
where
|
|
|
|
|
BD: BitDenotation<'tcx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
{
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
fn walk_cfg(&mut self, in_out: &mut BitSet<BD::Idx>) {
|
2019-06-03 22:26:48 +00:00
|
|
|
|
let body = self.builder.body;
|
2019-06-22 20:00:17 +00:00
|
|
|
|
|
|
|
|
|
// Initialize the dirty queue in reverse post-order. This makes it more likely that the
|
|
|
|
|
// entry state for each basic block will have the effects of its predecessors applied
|
|
|
|
|
// before it is processed. In fact, for CFGs without back edges, this guarantees that
|
|
|
|
|
// dataflow will converge in exactly `N` iterations, where `N` is the number of basic
|
|
|
|
|
// blocks.
|
|
|
|
|
let mut dirty_queue: WorkQueue<mir::BasicBlock> =
|
|
|
|
|
WorkQueue::with_none(body.basic_blocks().len());
|
|
|
|
|
for (bb, _) in traversal::reverse_postorder(body) {
|
|
|
|
|
dirty_queue.insert(bb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add blocks which are not reachable from START_BLOCK to the work queue. These blocks will
|
|
|
|
|
// be processed after the ones added above.
|
|
|
|
|
for bb in body.basic_blocks().indices() {
|
|
|
|
|
dirty_queue.insert(bb);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-02 18:48:54 +00:00
|
|
|
|
while let Some(bb) = dirty_queue.pop() {
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
let (on_entry, trans) = self.builder.flow_state.sets.get_mut(bb.index());
|
|
|
|
|
debug_assert!(in_out.words().len() == on_entry.words().len());
|
|
|
|
|
in_out.overwrite(on_entry);
|
|
|
|
|
trans.apply(in_out);
|
|
|
|
|
|
2019-06-03 22:26:48 +00:00
|
|
|
|
let bb_data = &body[bb];
|
2018-07-02 18:48:54 +00:00
|
|
|
|
self.builder.propagate_bits_into_graph_successors_of(
|
2019-12-22 22:42:04 +00:00
|
|
|
|
in_out,
|
|
|
|
|
(bb, bb_data),
|
|
|
|
|
&mut dirty_queue,
|
|
|
|
|
);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-05 14:37:21 +00:00
|
|
|
|
fn dataflow_path(context: &str, path: &str) -> PathBuf {
|
2016-05-20 11:40:52 +00:00
|
|
|
|
let mut path = PathBuf::from(path);
|
|
|
|
|
let new_file_name = {
|
|
|
|
|
let orig_file_name = path.file_name().unwrap().to_str().unwrap();
|
|
|
|
|
format!("{}_{}", context, orig_file_name)
|
|
|
|
|
};
|
|
|
|
|
path.set_file_name(new_file_name);
|
|
|
|
|
path
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-16 09:41:24 +00:00
|
|
|
|
impl<'a, 'tcx, BD> DataflowBuilder<'a, 'tcx, BD>
|
|
|
|
|
where
|
|
|
|
|
BD: BitDenotation<'tcx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
{
|
2016-05-24 14:16:42 +00:00
|
|
|
|
fn pre_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
|
2019-12-22 22:42:04 +00:00
|
|
|
|
where
|
|
|
|
|
P: Fn(&BD, BD::Idx) -> DebugFormatted,
|
2016-05-24 14:16:42 +00:00
|
|
|
|
{
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
if let Some(ref path_str) = self.print_preflow_to {
|
2018-09-05 14:37:21 +00:00
|
|
|
|
let path = dataflow_path(BD::name(), path_str);
|
2016-05-24 14:16:42 +00:00
|
|
|
|
graphviz::print_borrowck_graph_to(self, &path, p)
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
} else {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-24 14:16:42 +00:00
|
|
|
|
fn post_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
|
2019-12-22 22:42:04 +00:00
|
|
|
|
where
|
|
|
|
|
P: Fn(&BD, BD::Idx) -> DebugFormatted,
|
2016-05-24 14:16:42 +00:00
|
|
|
|
{
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
if let Some(ref path_str) = self.print_postflow_to {
|
2018-09-05 14:37:21 +00:00
|
|
|
|
let path = dataflow_path(BD::name(), path_str);
|
2016-05-24 14:16:42 +00:00
|
|
|
|
graphviz::print_borrowck_graph_to(self, &path, p)
|
2018-09-05 14:37:21 +00:00
|
|
|
|
} else {
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-05 12:52:18 +00:00
|
|
|
|
/// DataflowResultsConsumer abstracts over walking the MIR with some
|
|
|
|
|
/// already constructed dataflow results.
|
|
|
|
|
///
|
|
|
|
|
/// It abstracts over the FlowState and also completely hides the
|
|
|
|
|
/// underlying flow analysis results, because it needs to handle cases
|
|
|
|
|
/// where we are combining the results of *multiple* flow analyses
|
2018-11-27 02:59:49 +00:00
|
|
|
|
/// (e.g., borrows + inits + uninits).
|
2019-06-16 09:33:47 +00:00
|
|
|
|
pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> {
|
2017-12-07 15:00:26 +00:00
|
|
|
|
type FlowState: FlowsAtLocation;
|
2017-07-05 12:52:18 +00:00
|
|
|
|
|
|
|
|
|
// Observation Hooks: override (at least one of) these to get analysis feedback.
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn visit_block_entry(&mut self, _bb: BasicBlock, _flow_state: &Self::FlowState) {}
|
2017-07-05 12:52:18 +00:00
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn visit_statement_entry(
|
|
|
|
|
&mut self,
|
|
|
|
|
_loc: Location,
|
|
|
|
|
_stmt: &'a Statement<'tcx>,
|
|
|
|
|
_flow_state: &Self::FlowState,
|
|
|
|
|
) {
|
|
|
|
|
}
|
2017-07-05 12:52:18 +00:00
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn visit_terminator_entry(
|
|
|
|
|
&mut self,
|
|
|
|
|
_loc: Location,
|
|
|
|
|
_term: &'a Terminator<'tcx>,
|
|
|
|
|
_flow_state: &Self::FlowState,
|
|
|
|
|
) {
|
|
|
|
|
}
|
2017-07-05 12:52:18 +00:00
|
|
|
|
|
|
|
|
|
// Main entry point: this drives the processing of results.
|
|
|
|
|
|
|
|
|
|
fn analyze_results(&mut self, flow_uninit: &mut Self::FlowState) {
|
|
|
|
|
let flow = flow_uninit;
|
2019-06-03 22:26:48 +00:00
|
|
|
|
for (bb, _) in traversal::reverse_postorder(self.body()) {
|
2017-12-07 15:00:26 +00:00
|
|
|
|
flow.reset_to_entry_of(bb);
|
2017-07-05 12:52:18 +00:00
|
|
|
|
self.process_basic_block(bb, flow);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn process_basic_block(&mut self, bb: BasicBlock, flow_state: &mut Self::FlowState) {
|
2019-07-09 21:28:02 +00:00
|
|
|
|
self.visit_block_entry(bb, flow_state);
|
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
let BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = self.body()[bb];
|
2017-07-05 12:52:18 +00:00
|
|
|
|
let mut location = Location { block: bb, statement_index: 0 };
|
|
|
|
|
for stmt in statements.iter() {
|
2017-12-07 15:00:26 +00:00
|
|
|
|
flow_state.reconstruct_statement_effect(location);
|
2017-07-05 12:52:18 +00:00
|
|
|
|
self.visit_statement_entry(location, stmt, flow_state);
|
2017-12-07 15:00:26 +00:00
|
|
|
|
flow_state.apply_local_effect(location);
|
2017-07-05 12:52:18 +00:00
|
|
|
|
location.statement_index += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(ref term) = *terminator {
|
2017-12-07 15:00:26 +00:00
|
|
|
|
flow_state.reconstruct_terminator_effect(location);
|
2017-07-05 12:52:18 +00:00
|
|
|
|
self.visit_terminator_entry(location, term, flow_state);
|
|
|
|
|
|
|
|
|
|
// We don't need to apply the effect of the terminator,
|
|
|
|
|
// since we are only visiting dataflow state on control
|
|
|
|
|
// flow entry to the various nodes. (But we still need to
|
|
|
|
|
// reconstruct the effect, because the visit method might
|
|
|
|
|
// inspect it.)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Delegated Hooks: Provide access to the MIR and process the flow state.
|
|
|
|
|
|
2019-06-03 22:26:48 +00:00
|
|
|
|
fn body(&self) -> &'a Body<'tcx>;
|
2017-07-05 12:52:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-18 02:01:16 +00:00
|
|
|
|
/// Allows iterating dataflow results in a flexible and reasonably fast way.
|
2019-06-26 21:08:33 +00:00
|
|
|
|
pub struct DataflowResultsCursor<'mir, 'tcx, BD, DR = DataflowResults<'tcx, BD>>
|
2019-06-18 02:01:16 +00:00
|
|
|
|
where
|
|
|
|
|
BD: BitDenotation<'tcx>,
|
|
|
|
|
DR: Borrow<DataflowResults<'tcx, BD>>,
|
|
|
|
|
{
|
|
|
|
|
flow_state: FlowAtLocation<'tcx, BD, DR>,
|
|
|
|
|
|
|
|
|
|
// The statement (or terminator) whose effect has been reconstructed in
|
|
|
|
|
// flow_state.
|
|
|
|
|
curr_loc: Option<Location>,
|
|
|
|
|
|
|
|
|
|
body: &'mir Body<'tcx>,
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-01 19:19:21 +00:00
|
|
|
|
pub type DataflowResultsRefCursor<'mir, 'tcx, BD> =
|
|
|
|
|
DataflowResultsCursor<'mir, 'tcx, BD, &'mir DataflowResults<'tcx, BD>>;
|
2019-06-18 02:01:16 +00:00
|
|
|
|
|
|
|
|
|
impl<'mir, 'tcx, BD, DR> DataflowResultsCursor<'mir, 'tcx, BD, DR>
|
|
|
|
|
where
|
|
|
|
|
BD: BitDenotation<'tcx>,
|
|
|
|
|
DR: Borrow<DataflowResults<'tcx, BD>>,
|
|
|
|
|
{
|
|
|
|
|
pub fn new(result: DR, body: &'mir Body<'tcx>) -> Self {
|
2019-12-22 22:42:04 +00:00
|
|
|
|
DataflowResultsCursor { flow_state: FlowAtLocation::new(result), curr_loc: None, body }
|
2019-06-18 02:01:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Seek to the given location in MIR. This method is fast if you are
|
|
|
|
|
/// traversing your MIR statements in order.
|
|
|
|
|
///
|
|
|
|
|
/// After calling `seek`, the current state will reflect all effects up to
|
|
|
|
|
/// and including the `before_statement_effect` of the statement at location
|
|
|
|
|
/// `loc`. The `statement_effect` of the statement at `loc` will be
|
|
|
|
|
/// available as the current effect (see e.g. `each_gen_bit`).
|
|
|
|
|
///
|
|
|
|
|
/// If `loc.statement_index` equals the number of statements in the block,
|
|
|
|
|
/// we will reconstruct the terminator effect in the same way as described
|
|
|
|
|
/// above.
|
|
|
|
|
pub fn seek(&mut self, loc: Location) {
|
|
|
|
|
if self.curr_loc.map(|cur| loc == cur).unwrap_or(false) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let start_index;
|
|
|
|
|
let should_reset = match self.curr_loc {
|
|
|
|
|
None => true,
|
2019-12-22 22:42:04 +00:00
|
|
|
|
Some(cur) if loc.block != cur.block || loc.statement_index < cur.statement_index => {
|
|
|
|
|
true
|
|
|
|
|
}
|
2019-06-18 02:01:16 +00:00
|
|
|
|
_ => false,
|
|
|
|
|
};
|
|
|
|
|
if should_reset {
|
|
|
|
|
self.flow_state.reset_to_entry_of(loc.block);
|
|
|
|
|
start_index = 0;
|
|
|
|
|
} else {
|
|
|
|
|
let curr_loc = self.curr_loc.unwrap();
|
|
|
|
|
start_index = curr_loc.statement_index;
|
|
|
|
|
// Apply the effect from the last seek to the current state.
|
|
|
|
|
self.flow_state.apply_local_effect(curr_loc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for stmt in start_index..loc.statement_index {
|
|
|
|
|
let mut stmt_loc = loc;
|
|
|
|
|
stmt_loc.statement_index = stmt;
|
|
|
|
|
self.flow_state.reconstruct_statement_effect(stmt_loc);
|
|
|
|
|
self.flow_state.apply_local_effect(stmt_loc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if loc.statement_index == self.body[loc.block].statements.len() {
|
|
|
|
|
self.flow_state.reconstruct_terminator_effect(loc);
|
|
|
|
|
} else {
|
|
|
|
|
self.flow_state.reconstruct_statement_effect(loc);
|
|
|
|
|
}
|
|
|
|
|
self.curr_loc = Some(loc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Return whether the current state contains bit `x`.
|
|
|
|
|
pub fn contains(&self, x: BD::Idx) -> bool {
|
|
|
|
|
self.flow_state.contains(x)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Iterate over each `gen` bit in the current effect (invoke `seek` first).
|
|
|
|
|
pub fn each_gen_bit<F>(&self, f: F)
|
|
|
|
|
where
|
|
|
|
|
F: FnMut(BD::Idx),
|
|
|
|
|
{
|
|
|
|
|
self.flow_state.each_gen_bit(f)
|
|
|
|
|
}
|
2017-12-23 22:45:53 +00:00
|
|
|
|
|
2019-08-30 03:47:45 +00:00
|
|
|
|
pub fn get(&self) -> &BitSet<BD::Idx> {
|
|
|
|
|
self.flow_state.as_dense()
|
2017-09-10 20:34:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-16 09:41:24 +00:00
|
|
|
|
pub struct DataflowAnalysis<'a, 'tcx, O>
|
|
|
|
|
where
|
|
|
|
|
O: BitDenotation<'tcx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
{
|
2018-12-17 16:26:24 +00:00
|
|
|
|
flow_state: DataflowState<'tcx, O>,
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
dead_unwinds: &'a BitSet<mir::BasicBlock>,
|
2019-06-03 22:26:48 +00:00
|
|
|
|
body: &'a Body<'tcx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-16 09:41:24 +00:00
|
|
|
|
impl<'a, 'tcx, O> DataflowAnalysis<'a, 'tcx, O>
|
|
|
|
|
where
|
|
|
|
|
O: BitDenotation<'tcx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
{
|
2018-12-17 16:26:24 +00:00
|
|
|
|
pub fn results(self) -> DataflowResults<'tcx, O> {
|
2016-05-24 13:01:48 +00:00
|
|
|
|
DataflowResults(self.flow_state)
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
pub fn body(&self) -> &'a Body<'tcx> {
|
|
|
|
|
self.body
|
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
pub struct DataflowResults<'tcx, O>(pub(crate) DataflowState<'tcx, O>)
|
|
|
|
|
where
|
|
|
|
|
O: BitDenotation<'tcx>;
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
|
2018-12-17 16:26:24 +00:00
|
|
|
|
impl<'tcx, O: BitDenotation<'tcx>> DataflowResults<'tcx, O> {
|
2016-05-27 12:07:08 +00:00
|
|
|
|
pub fn sets(&self) -> &AllSets<O::Idx> {
|
2016-05-16 23:26:18 +00:00
|
|
|
|
&self.0.sets
|
|
|
|
|
}
|
2017-07-05 12:52:18 +00:00
|
|
|
|
|
|
|
|
|
pub fn operator(&self) -> &O {
|
|
|
|
|
&self.0.operator
|
|
|
|
|
}
|
2016-05-16 23:26:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-05 12:52:18 +00:00
|
|
|
|
/// State of a dataflow analysis; couples a collection of bit sets
|
|
|
|
|
/// with operator used to initialize and merge bits during analysis.
|
2019-12-22 22:42:04 +00:00
|
|
|
|
pub struct DataflowState<'tcx, O: BitDenotation<'tcx>> {
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// All the sets for the analysis. (Factored into its
|
|
|
|
|
/// own structure so that we can borrow it mutably
|
|
|
|
|
/// on its own separate from other fields.)
|
2016-05-23 16:26:52 +00:00
|
|
|
|
pub sets: AllSets<O::Idx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
|
|
|
|
|
/// operator used to initialize, combine, and interpret bits.
|
2017-06-26 12:57:26 +00:00
|
|
|
|
pub(crate) operator: O,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-17 16:26:24 +00:00
|
|
|
|
impl<'tcx, O: BitDenotation<'tcx>> DataflowState<'tcx, O> {
|
2019-12-22 22:42:04 +00:00
|
|
|
|
pub(crate) fn interpret_set<'c, P>(
|
|
|
|
|
&self,
|
|
|
|
|
o: &'c O,
|
|
|
|
|
set: &BitSet<O::Idx>,
|
|
|
|
|
render_idx: &P,
|
|
|
|
|
) -> Vec<DebugFormatted>
|
|
|
|
|
where
|
|
|
|
|
P: Fn(&O, O::Idx) -> DebugFormatted,
|
2017-07-04 13:12:11 +00:00
|
|
|
|
{
|
2018-08-14 00:21:24 +00:00
|
|
|
|
set.iter().map(|i| render_idx(o, i)).collect()
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
pub(crate) fn interpret_hybrid_set<'c, P>(
|
|
|
|
|
&self,
|
|
|
|
|
o: &'c O,
|
|
|
|
|
set: &HybridBitSet<O::Idx>,
|
|
|
|
|
render_idx: &P,
|
|
|
|
|
) -> Vec<DebugFormatted>
|
|
|
|
|
where
|
|
|
|
|
P: Fn(&O, O::Idx) -> DebugFormatted,
|
2018-08-14 00:21:24 +00:00
|
|
|
|
{
|
|
|
|
|
set.iter().map(|i| render_idx(o, i)).collect()
|
2017-07-04 13:12:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
/// A 2-tuple representing the "gen" and "kill" bitsets during
|
|
|
|
|
/// dataflow analysis.
|
2017-07-05 13:11:23 +00:00
|
|
|
|
///
|
|
|
|
|
/// It is best to ensure that the intersection of `gen_set` and
|
|
|
|
|
/// `kill_set` is empty; otherwise the results of the dataflow will
|
|
|
|
|
/// have a hidden dependency on what order the bits are generated and
|
|
|
|
|
/// killed during the iteration. (This is such a good idea that the
|
|
|
|
|
/// `fn gen` and `fn kill` methods that set their state enforce this
|
|
|
|
|
/// for you.)
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub struct GenKill<T> {
|
|
|
|
|
pub(crate) gen_set: T,
|
|
|
|
|
pub(crate) kill_set: T,
|
|
|
|
|
}
|
2017-07-05 13:11:23 +00:00
|
|
|
|
|
2019-09-06 05:31:09 +00:00
|
|
|
|
pub type GenKillSet<T> = GenKill<HybridBitSet<T>>;
|
2017-07-05 13:11:23 +00:00
|
|
|
|
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
impl<T> GenKill<T> {
|
|
|
|
|
/// Creates a new tuple where `gen_set == kill_set == elem`.
|
|
|
|
|
pub(crate) fn from_elem(elem: T) -> Self
|
2019-12-22 22:42:04 +00:00
|
|
|
|
where
|
|
|
|
|
T: Clone,
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
{
|
2019-12-22 22:42:04 +00:00
|
|
|
|
GenKill { gen_set: elem.clone(), kill_set: elem }
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
impl<E: Idx> GenKillSet<E> {
|
2019-09-06 05:31:09 +00:00
|
|
|
|
pub fn clear(&mut self) {
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
self.gen_set.clear();
|
|
|
|
|
self.kill_set.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 05:31:09 +00:00
|
|
|
|
pub fn gen(&mut self, e: E) {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
self.gen_set.insert(e);
|
2016-05-23 16:26:52 +00:00
|
|
|
|
self.kill_set.remove(e);
|
|
|
|
|
}
|
2019-07-31 19:00:35 +00:00
|
|
|
|
|
2019-09-06 05:31:09 +00:00
|
|
|
|
pub fn gen_all(&mut self, i: impl IntoIterator<Item: Borrow<E>>) {
|
2017-12-03 23:00:46 +00:00
|
|
|
|
for j in i {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
self.gen(*j.borrow());
|
2017-12-03 23:00:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 05:31:09 +00:00
|
|
|
|
pub fn kill(&mut self, e: E) {
|
2016-05-23 16:26:52 +00:00
|
|
|
|
self.gen_set.remove(e);
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
self.kill_set.insert(e);
|
2016-05-23 16:26:52 +00:00
|
|
|
|
}
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
|
2019-09-06 05:31:09 +00:00
|
|
|
|
pub fn kill_all(&mut self, i: impl IntoIterator<Item: Borrow<E>>) {
|
2017-12-03 23:00:46 +00:00
|
|
|
|
for j in i {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
self.kill(*j.borrow());
|
2017-12-03 23:00:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
/// Computes `(set ∪ gen) - kill` and assigns the result to `set`.
|
|
|
|
|
pub(crate) fn apply(&self, set: &mut BitSet<E>) {
|
|
|
|
|
set.union(&self.gen_set);
|
|
|
|
|
set.subtract(&self.kill_set);
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
}
|
2016-05-23 16:26:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct AllSets<E: Idx> {
|
|
|
|
|
/// Analysis bitwidth for each block.
|
|
|
|
|
bits_per_block: usize,
|
|
|
|
|
|
|
|
|
|
/// For each block, bits valid on entry to the block.
|
|
|
|
|
on_entry: Vec<BitSet<E>>,
|
|
|
|
|
|
|
|
|
|
/// The transfer function of each block expressed as the set of bits
|
|
|
|
|
/// generated and killed by executing the statements + terminator in the
|
|
|
|
|
/// block -- with one caveat. In particular, for *call terminators*, the
|
|
|
|
|
/// effect of storing the destination is not included, since that only takes
|
|
|
|
|
/// effect on the **success** edge (and not the unwind edge).
|
|
|
|
|
trans: Vec<GenKillSet<E>>,
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
impl<E: Idx> AllSets<E> {
|
|
|
|
|
pub fn bits_per_block(&self) -> usize {
|
|
|
|
|
self.bits_per_block
|
|
|
|
|
}
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
|
|
|
|
|
pub fn get_mut(&mut self, block_idx: usize) -> (&mut BitSet<E>, &mut GenKillSet<E>) {
|
|
|
|
|
(&mut self.on_entry[block_idx], &mut self.trans[block_idx])
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
pub fn trans_for(&self, block_idx: usize) -> &GenKillSet<E> {
|
|
|
|
|
&self.trans[block_idx]
|
|
|
|
|
}
|
|
|
|
|
pub fn trans_mut_for(&mut self, block_idx: usize) -> &mut GenKillSet<E> {
|
|
|
|
|
&mut self.trans[block_idx]
|
|
|
|
|
}
|
|
|
|
|
pub fn entry_set_for(&self, block_idx: usize) -> &BitSet<E> {
|
|
|
|
|
&self.on_entry[block_idx]
|
|
|
|
|
}
|
|
|
|
|
pub fn entry_set_mut_for(&mut self, block_idx: usize) -> &mut BitSet<E> {
|
|
|
|
|
&mut self.on_entry[block_idx]
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
pub fn gen_set_for(&self, block_idx: usize) -> &HybridBitSet<E> {
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
&self.trans_for(block_idx).gen_set
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
pub fn kill_set_for(&self, block_idx: usize) -> &HybridBitSet<E> {
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
&self.trans_for(block_idx).kill_set
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Parameterization for the precise form of data flow that is used.
|
2019-06-21 19:39:01 +00:00
|
|
|
|
///
|
|
|
|
|
/// `BottomValue` determines whether the initial entry set for each basic block is empty or full.
|
|
|
|
|
/// This also determines the semantics of the lattice `join` operator used to merge dataflow
|
|
|
|
|
/// results, since dataflow works by starting at the bottom and moving monotonically to a fixed
|
|
|
|
|
/// point.
|
|
|
|
|
///
|
|
|
|
|
/// This means, for propagation across the graph, that you either want to start at all-zeroes and
|
|
|
|
|
/// then use Union as your merge when propagating, or you start at all-ones and then use Intersect
|
|
|
|
|
/// as your merge when propagating.
|
|
|
|
|
pub trait BottomValue {
|
|
|
|
|
/// Specifies the initial value for each bit in the entry set for each basic block.
|
|
|
|
|
const BOTTOM_VALUE: bool;
|
|
|
|
|
|
|
|
|
|
/// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed.
|
2019-12-15 08:42:09 +00:00
|
|
|
|
///
|
2019-12-20 18:46:38 +00:00
|
|
|
|
/// It is almost certainly wrong to override this, since it automatically applies
|
2019-12-15 08:42:09 +00:00
|
|
|
|
/// * `inout_set & in_set` if `BOTTOM_VALUE == true`
|
|
|
|
|
/// * `inout_set | in_set` if `BOTTOM_VALUE == false`
|
|
|
|
|
///
|
|
|
|
|
/// This means that if a bit is not `BOTTOM_VALUE`, it is propagated into all target blocks.
|
|
|
|
|
/// For clarity, the above statement again from a different perspective:
|
2019-12-20 18:46:38 +00:00
|
|
|
|
/// A bit in the block's entry set is `!BOTTOM_VALUE` if *any* predecessor block's bit value is
|
2019-12-15 08:42:09 +00:00
|
|
|
|
/// `!BOTTOM_VALUE`.
|
2019-12-20 18:46:38 +00:00
|
|
|
|
///
|
2019-12-15 08:42:09 +00:00
|
|
|
|
/// There are situations where you want the opposite behaviour: propagate only if *all*
|
2019-12-20 18:46:38 +00:00
|
|
|
|
/// predecessor blocks's value is `!BOTTOM_VALUE`.
|
|
|
|
|
/// E.g. if you want to know whether a bit is *definitely* set at a specific location. This
|
|
|
|
|
/// means that all code paths leading to the location must have set the bit, instead of any
|
|
|
|
|
/// code path leading there.
|
|
|
|
|
///
|
|
|
|
|
/// If you want this kind of "definitely set" analysis, you need to
|
2019-12-15 08:42:09 +00:00
|
|
|
|
/// 1. Invert `BOTTOM_VALUE`
|
|
|
|
|
/// 2. Reset the `entry_set` in `start_block_effect` to `!BOTTOM_VALUE`
|
|
|
|
|
/// 3. Override `join` to do the opposite from what it's doing now.
|
2019-06-21 19:39:01 +00:00
|
|
|
|
#[inline]
|
|
|
|
|
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
|
2020-02-28 12:36:45 +00:00
|
|
|
|
if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) }
|
2019-06-21 19:39:01 +00:00
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
/// A specific flavor of dataflow analysis.
|
|
|
|
|
///
|
|
|
|
|
/// To run a dataflow analysis, one sets up an initial state for the
|
|
|
|
|
/// `START_BLOCK` via `start_block_effect` and a transfer function (`trans`)
|
|
|
|
|
/// for each block individually. The entry set for all other basic blocks is
|
2019-06-21 19:39:01 +00:00
|
|
|
|
/// initialized to `Self::BOTTOM_VALUE`. The dataflow analysis then
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
/// iteratively modifies the various entry sets (but leaves the the transfer
|
2019-12-15 08:42:09 +00:00
|
|
|
|
/// function unchanged). `BottomValue::join` is used to merge the bitsets from
|
|
|
|
|
/// two blocks (e.g. when two blocks' terminator jumps to a single block, that
|
|
|
|
|
/// target block's state is the merged state of both incoming blocks).
|
2019-06-21 19:39:01 +00:00
|
|
|
|
pub trait BitDenotation<'tcx>: BottomValue {
|
2016-05-23 16:26:52 +00:00
|
|
|
|
/// Specifies what index type is used to access the bitvector.
|
|
|
|
|
type Idx: Idx;
|
|
|
|
|
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// A name describing the dataflow analysis that this
|
2019-02-08 13:53:55 +00:00
|
|
|
|
/// `BitDenotation` is supporting. The name should be something
|
|
|
|
|
/// suitable for plugging in as part of a filename (i.e., avoid
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// space-characters or other things that tend to look bad on a
|
2019-02-08 13:53:55 +00:00
|
|
|
|
/// file system, like slashes or periods). It is also better for
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// the name to be reasonably short, again because it will be
|
|
|
|
|
/// plugged into a filename.
|
|
|
|
|
fn name() -> &'static str;
|
|
|
|
|
|
|
|
|
|
/// Size of each bitvector allocated for each block in the analysis.
|
2016-12-26 14:40:15 +00:00
|
|
|
|
fn bits_per_block(&self) -> usize;
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
|
2017-12-07 18:06:55 +00:00
|
|
|
|
/// Mutates the entry set according to the effects that
|
|
|
|
|
/// have been established *prior* to entering the start
|
|
|
|
|
/// block. This can't access the gen/kill sets, because
|
|
|
|
|
/// these won't be accounted for correctly.
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
///
|
|
|
|
|
/// (For example, establishing the call arguments.)
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
fn start_block_effect(&self, entry_set: &mut BitSet<Self::Idx>);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
|
2017-12-23 22:45:53 +00:00
|
|
|
|
/// Similar to `statement_effect`, except it applies
|
|
|
|
|
/// *just before* the statement rather than *just after* it.
|
|
|
|
|
///
|
|
|
|
|
/// This matters for "dataflow at location" APIs, because the
|
|
|
|
|
/// before-statement effect is visible while visiting the
|
|
|
|
|
/// statement, while the after-statement effect only becomes
|
|
|
|
|
/// visible at the next statement.
|
|
|
|
|
///
|
|
|
|
|
/// Both the before-statement and after-statement effects are
|
|
|
|
|
/// applied, in that order, before moving for the next
|
|
|
|
|
/// statement.
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn before_statement_effect(&self, _trans: &mut GenKillSet<Self::Idx>, _location: Location) {}
|
2017-12-23 22:45:53 +00:00
|
|
|
|
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// Mutates the block-sets (the flow sets for the given
|
|
|
|
|
/// basic block) according to the effects of evaluating statement.
|
|
|
|
|
///
|
|
|
|
|
/// This is used, in particular, for building up the
|
2017-08-11 18:34:14 +00:00
|
|
|
|
/// "transfer-function" representing the overall-effect of the
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// block, represented via GEN and KILL sets.
|
|
|
|
|
///
|
2016-05-25 12:52:40 +00:00
|
|
|
|
/// The statement is identified as `bb_data[idx_stmt]`, where
|
2017-08-11 18:34:14 +00:00
|
|
|
|
/// `bb_data` is the sequence of statements identified by `bb` in
|
2016-05-25 12:52:40 +00:00
|
|
|
|
/// the MIR.
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
|
2017-12-23 22:45:53 +00:00
|
|
|
|
/// Similar to `terminator_effect`, except it applies
|
|
|
|
|
/// *just before* the terminator rather than *just after* it.
|
|
|
|
|
///
|
|
|
|
|
/// This matters for "dataflow at location" APIs, because the
|
|
|
|
|
/// before-terminator effect is visible while visiting the
|
|
|
|
|
/// terminator, while the after-terminator effect only becomes
|
|
|
|
|
/// visible at the terminator's successors.
|
|
|
|
|
///
|
|
|
|
|
/// Both the before-terminator and after-terminator effects are
|
|
|
|
|
/// applied, in that order, before moving for the next
|
|
|
|
|
/// terminator.
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn before_terminator_effect(&self, _trans: &mut GenKillSet<Self::Idx>, _location: Location) {}
|
2017-12-23 22:45:53 +00:00
|
|
|
|
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// Mutates the block-sets (the flow sets for the given
|
|
|
|
|
/// basic block) according to the effects of evaluating
|
|
|
|
|
/// the terminator.
|
|
|
|
|
///
|
|
|
|
|
/// This is used, in particular, for building up the
|
2017-08-11 18:34:14 +00:00
|
|
|
|
/// "transfer-function" representing the overall-effect of the
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// block, represented via GEN and KILL sets.
|
|
|
|
|
///
|
|
|
|
|
/// The effects applied here cannot depend on which branch the
|
|
|
|
|
/// terminator took.
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
|
|
|
|
|
/// Mutates the block-sets according to the (flow-dependent)
|
|
|
|
|
/// effect of a successful return from a Call terminator.
|
|
|
|
|
///
|
|
|
|
|
/// If basic-block BB_x ends with a call-instruction that, upon
|
|
|
|
|
/// successful return, flows to BB_y, then this method will be
|
|
|
|
|
/// called on the exit flow-state of BB_x in order to set up the
|
|
|
|
|
/// entry flow-state of BB_y.
|
|
|
|
|
///
|
|
|
|
|
/// This is used, in particular, as a special case during the
|
|
|
|
|
/// "propagate" loop where all of the basic blocks are repeatedly
|
|
|
|
|
/// visited. Since the effects of a Call terminator are
|
|
|
|
|
/// flow-dependent, the current MIR cannot encode them via just
|
|
|
|
|
/// GEN and KILL sets attached to the block, and so instead we add
|
|
|
|
|
/// this extra machinery to represent the flow-dependent effect.
|
2019-02-08 13:53:55 +00:00
|
|
|
|
//
|
|
|
|
|
// FIXME: right now this is a bit of a wart in the API. It might
|
|
|
|
|
// be better to represent this as an additional gen- and
|
|
|
|
|
// kill-sets associated with each edge coming out of the basic
|
|
|
|
|
// block.
|
2018-12-17 16:26:24 +00:00
|
|
|
|
fn propagate_call_return(
|
|
|
|
|
&self,
|
|
|
|
|
in_out: &mut BitSet<Self::Idx>,
|
|
|
|
|
call_bb: mir::BasicBlock,
|
|
|
|
|
dest_bb: mir::BasicBlock,
|
|
|
|
|
dest_place: &mir::Place<'tcx>,
|
|
|
|
|
);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D>
|
|
|
|
|
where
|
|
|
|
|
D: BitDenotation<'tcx>,
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
{
|
2019-12-22 22:42:04 +00:00
|
|
|
|
pub fn new(
|
|
|
|
|
body: &'a Body<'tcx>,
|
|
|
|
|
dead_unwinds: &'a BitSet<mir::BasicBlock>,
|
|
|
|
|
denotation: D,
|
|
|
|
|
) -> Self {
|
2016-12-26 14:40:15 +00:00
|
|
|
|
let bits_per_block = denotation.bits_per_block();
|
2019-06-03 22:26:48 +00:00
|
|
|
|
let num_blocks = body.basic_blocks().len();
|
2018-03-05 07:44:10 +00:00
|
|
|
|
|
2020-02-24 15:52:40 +00:00
|
|
|
|
let on_entry = if D::BOTTOM_VALUE {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
vec![BitSet::new_filled(bits_per_block); num_blocks]
|
2016-05-23 16:26:52 +00:00
|
|
|
|
} else {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
vec![BitSet::new_empty(bits_per_block); num_blocks]
|
2018-08-17 00:41:14 +00:00
|
|
|
|
};
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
let nop = GenKill::from_elem(HybridBitSet::new_empty(bits_per_block));
|
2016-05-23 16:26:52 +00:00
|
|
|
|
|
|
|
|
|
DataflowAnalysis {
|
2019-06-03 22:26:48 +00:00
|
|
|
|
body,
|
2017-08-07 05:54:09 +00:00
|
|
|
|
dead_unwinds,
|
2016-05-23 16:26:52 +00:00
|
|
|
|
flow_state: DataflowState {
|
2019-12-22 22:42:04 +00:00
|
|
|
|
sets: AllSets { bits_per_block, on_entry, trans: vec![nop; num_blocks] },
|
2016-05-23 16:26:52 +00:00
|
|
|
|
operator: denotation,
|
2019-12-22 22:42:04 +00:00
|
|
|
|
},
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
New `ActiveBorrows` dataflow for two-phase `&mut`; not yet borrowed-checked.
High-level picture: The old `Borrows` analysis is now called
`Reservations` (implemented as a newtype wrapper around `Borrows`);
this continues to compute whether a `Rvalue::Ref` can reach a
statement without an intervening `EndRegion`. In addition, we also
track what `Place` each such `Rvalue::Ref` was immediately assigned
to in a given borrow (yay for MIR-structural properties!).
The new `ActiveBorrows` analysis then tracks the initial use of any of
those assigned `Places` for a given borrow. I.e. a borrow becomes
"active" immediately after it starts being "used" in some way. (This
is conservative in the sense that we will treat a copy `x = y;` as a
use of `y`; in principle one might further delay activation in such
cases.)
The new `ActiveBorrows` analysis needs to take the `Reservations`
results as an initial input, because the reservation state influences
the gen/kill sets for `ActiveBorrows`. In particular, a use of `a`
activates a borrow `a = &b` if and only if there exists a path (in the
control flow graph) from the borrow to that use. So we need to know if
the borrow reaches a given use to know if it really gets a gen-bit or
not.
* Incorporating the output from one dataflow analysis into the input
of another required more changes to the infrastructure than I had
expected, and even after those changes, the resulting code is still
a bit subtle.
* In particular, Since we need to know the intrablock reservation
state, we need to dynamically update a bitvector for the
reservations as we are also trying to compute the gen/kills
bitvector for the active borrows.
* The way I ended up deciding to do this (after also toying with at
least two other designs) is to put both the reservation state and
the active borrow state into a single bitvector. That is why we now
have separate (but related) `BorrowIndex` and
`ReserveOrActivateIndex`: each borrow index maps to a pair of
neighboring reservation and activation indexes.
As noted above, these changes are solely adding the active borrows
dataflow analysis (and updating the existing code to cope with the
switch from `Borrows` to `Reservations`). The code to process the
bitvector in the borrow checker currently just skips over all of the
active borrow bits.
But atop this commit, one *can* observe the analysis results by
looking at the graphviz output, e.g. via
```rust
#[rustc_mir(borrowck_graphviz_preflow="pre_two_phase.dot",
borrowck_graphviz_postflow="post_two_phase.dot")]
```
Includes doc for `FindPlaceUses`, as well as `Reservations` and
`ActiveBorrows` structs, which are wrappers are the `Borrows` struct
that dictate which flow analysis should be performed.
2017-12-01 11:32:51 +00:00
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-16 09:41:24 +00:00
|
|
|
|
impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D>
|
|
|
|
|
where
|
|
|
|
|
D: BitDenotation<'tcx>,
|
|
|
|
|
{
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// Propagates the bits of `in_out` into all the successors of `bb`,
|
|
|
|
|
/// using bitwise operator denoted by `self.operator`.
|
|
|
|
|
///
|
|
|
|
|
/// For most blocks, this is entirely uniform. However, for blocks
|
|
|
|
|
/// that end with a call terminator, the effect of the call on the
|
|
|
|
|
/// dataflow state may depend on whether the call returned
|
|
|
|
|
/// successfully or unwound.
|
|
|
|
|
///
|
|
|
|
|
/// To reflect this, the `propagate_call_return` method of the
|
|
|
|
|
/// `BitDenotation` mutates `in_out` when propagating `in_out` via
|
|
|
|
|
/// a call terminator; such mutation is performed *last*, to
|
2018-11-27 02:59:49 +00:00
|
|
|
|
/// ensure its side-effects do not leak elsewhere (e.g., into
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
/// unwind target).
|
|
|
|
|
fn propagate_bits_into_graph_successors_of(
|
|
|
|
|
&mut self,
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
in_out: &mut BitSet<D::Idx>,
|
2018-12-17 16:26:24 +00:00
|
|
|
|
(bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData<'tcx>),
|
2019-12-22 22:42:04 +00:00
|
|
|
|
dirty_list: &mut WorkQueue<mir::BasicBlock>,
|
|
|
|
|
) {
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
match bb_data.terminator().kind {
|
2019-12-22 22:42:04 +00:00
|
|
|
|
mir::TerminatorKind::Return
|
|
|
|
|
| mir::TerminatorKind::Resume
|
|
|
|
|
| mir::TerminatorKind::Abort
|
|
|
|
|
| mir::TerminatorKind::GeneratorDrop
|
|
|
|
|
| mir::TerminatorKind::Unreachable => {}
|
|
|
|
|
mir::TerminatorKind::Goto { target }
|
|
|
|
|
| mir::TerminatorKind::Assert { target, cleanup: None, .. }
|
|
|
|
|
| mir::TerminatorKind::Yield { resume: target, drop: None, .. }
|
|
|
|
|
| mir::TerminatorKind::Drop { target, location: _, unwind: None }
|
|
|
|
|
| mir::TerminatorKind::DropAndReplace { target, value: _, location: _, unwind: None } =>
|
|
|
|
|
{
|
2018-07-02 18:48:54 +00:00
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
2018-07-02 18:48:54 +00:00
|
|
|
|
mir::TerminatorKind::Yield { resume: target, drop: Some(drop), .. } => {
|
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
|
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, drop, dirty_list);
|
2016-12-26 13:34:03 +00:00
|
|
|
|
}
|
2019-12-22 22:42:04 +00:00
|
|
|
|
mir::TerminatorKind::Assert { target, cleanup: Some(unwind), .. }
|
|
|
|
|
| mir::TerminatorKind::Drop { target, location: _, unwind: Some(unwind) }
|
|
|
|
|
| mir::TerminatorKind::DropAndReplace {
|
|
|
|
|
target,
|
|
|
|
|
value: _,
|
|
|
|
|
location: _,
|
|
|
|
|
unwind: Some(unwind),
|
2016-05-16 22:06:52 +00:00
|
|
|
|
} => {
|
2018-07-02 18:48:54 +00:00
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
if !self.dead_unwinds.contains(bb) {
|
2018-07-02 18:48:54 +00:00
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
|
2017-04-06 22:00:53 +00:00
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
2016-09-19 20:50:00 +00:00
|
|
|
|
mir::TerminatorKind::SwitchInt { ref targets, .. } => {
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
for target in targets {
|
2018-07-02 18:48:54 +00:00
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-29 09:34:12 +00:00
|
|
|
|
mir::TerminatorKind::Call { cleanup, ref destination, .. } => {
|
2018-07-02 18:48:54 +00:00
|
|
|
|
if let Some(unwind) = cleanup {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
if !self.dead_unwinds.contains(bb) {
|
2018-07-02 18:48:54 +00:00
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
|
2017-04-06 22:00:53 +00:00
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
2018-07-02 18:48:54 +00:00
|
|
|
|
if let Some((ref dest_place, dest_bb)) = *destination {
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
// N.B.: This must be done *last*, after all other
|
|
|
|
|
// propagation, as documented in comment above.
|
2019-12-22 22:42:04 +00:00
|
|
|
|
self.flow_state.operator.propagate_call_return(in_out, bb, dest_bb, dest_place);
|
2018-07-02 18:48:54 +00:00
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, dest_bb, dirty_list);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-06 14:18:57 +00:00
|
|
|
|
mir::TerminatorKind::FalseEdges { real_target, imaginary_target } => {
|
2018-07-02 18:48:54 +00:00
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list);
|
2019-05-06 14:18:57 +00:00
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, imaginary_target, dirty_list);
|
2017-10-13 13:36:15 +00:00
|
|
|
|
}
|
2018-07-02 18:48:54 +00:00
|
|
|
|
mir::TerminatorKind::FalseUnwind { real_target, unwind } => {
|
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list);
|
|
|
|
|
if let Some(unwind) = unwind {
|
Merge indexed_set.rs into bitvec.rs, and rename it bit_set.rs.
Currently we have two files implementing bitsets (and 2D bit matrices).
This commit combines them into one, taking the best features from each.
This involves renaming a lot of things. The high level changes are as
follows.
- bitvec.rs --> bit_set.rs
- indexed_set.rs --> (removed)
- BitArray + IdxSet --> BitSet (merged, see below)
- BitVector --> GrowableBitSet
- {,Sparse,Hybrid}IdxSet --> {,Sparse,Hybrid}BitSet
- BitMatrix --> BitMatrix
- SparseBitMatrix --> SparseBitMatrix
The changes within the bitset types themselves are as follows.
```
OLD OLD NEW
BitArray<C> IdxSet<T> BitSet<T>
-------- ------ ------
grow - grow
new - (remove)
new_empty new_empty new_empty
new_filled new_filled new_filled
- to_hybrid to_hybrid
clear clear clear
set_up_to set_up_to set_up_to
clear_above - clear_above
count - count
contains(T) contains(&T) contains(T)
contains_all - superset
is_empty - is_empty
insert(T) add(&T) insert(T)
insert_all - insert_all()
remove(T) remove(&T) remove(T)
words words words
words_mut words_mut words_mut
- overwrite overwrite
merge union union
- subtract subtract
- intersect intersect
iter iter iter
```
In general, when choosing names I went with:
- names that are more obvious (e.g. `BitSet` over `IdxSet`).
- names that are more like the Rust libraries (e.g. `T` over `C`,
`insert` over `add`);
- names that are more set-like (e.g. `union` over `merge`, `superset`
over `contains_all`, `domain_size` over `num_bits`).
Also, using `T` for index arguments seems more sensible than `&T` --
even though the latter is standard in Rust collection types -- because
indices are always copyable. It also results in fewer `&` and `*`
sigils in practice.
2018-09-14 05:07:25 +00:00
|
|
|
|
if !self.dead_unwinds.contains(bb) {
|
2018-07-02 18:48:54 +00:00
|
|
|
|
self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
|
2018-01-25 06:45:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
|
fn propagate_bits_into_entry_set_for(
|
|
|
|
|
&mut self,
|
|
|
|
|
in_out: &BitSet<D::Idx>,
|
|
|
|
|
bb: mir::BasicBlock,
|
|
|
|
|
dirty_queue: &mut WorkQueue<mir::BasicBlock>,
|
|
|
|
|
) {
|
rustc_mir: don't pass `on_entry` when building transfer functions.
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
2019-06-12 22:00:43 +00:00
|
|
|
|
let entry_set = self.flow_state.sets.entry_set_mut_for(bb.index());
|
2018-09-17 03:52:35 +00:00
|
|
|
|
let set_changed = self.flow_state.operator.join(entry_set, &in_out);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
if set_changed {
|
2018-07-02 18:48:54 +00:00
|
|
|
|
dirty_queue.insert(bb);
|
Revised mir-dataflow.
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.)
2016-05-02 13:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|