Rollup merge of #77296 - tmiasko:liveness-option, r=ecstatic-morse
liveness: Use Option::None to represent absent live nodes No functional changes intended.
This commit is contained in:
commit
d4add198be
1 changed files with 36 additions and 40 deletions
|
@ -62,13 +62,13 @@
|
||||||
//! - `reader`: the `LiveNode` ID of some node which will read the value
|
//! - `reader`: the `LiveNode` ID of some node which will read the value
|
||||||
//! that `V` holds on entry to `N`. Formally: a node `M` such
|
//! that `V` holds on entry to `N`. Formally: a node `M` such
|
||||||
//! that there exists a path `P` from `N` to `M` where `P` does not
|
//! that there exists a path `P` from `N` to `M` where `P` does not
|
||||||
//! write `V`. If the `reader` is `INVALID_NODE`, then the current
|
//! write `V`. If the `reader` is `None`, then the current
|
||||||
//! value will never be read (the variable is dead, essentially).
|
//! value will never be read (the variable is dead, essentially).
|
||||||
//!
|
//!
|
||||||
//! - `writer`: the `LiveNode` ID of some node which will write the
|
//! - `writer`: the `LiveNode` ID of some node which will write the
|
||||||
//! variable `V` and which is reachable from `N`. Formally: a node `M`
|
//! variable `V` and which is reachable from `N`. Formally: a node `M`
|
||||||
//! such that there exists a path `P` from `N` to `M` and `M` writes
|
//! such that there exists a path `P` from `N` to `M` and `M` writes
|
||||||
//! `V`. If the `writer` is `INVALID_NODE`, then there is no writer
|
//! `V`. If the `writer` is `None`, then there is no writer
|
||||||
//! of `V` that follows `N`.
|
//! of `V` that follows `N`.
|
||||||
//!
|
//!
|
||||||
//! - `used`: a boolean value indicating whether `V` is *used*. We
|
//! - `used`: a boolean value indicating whether `V` is *used*. We
|
||||||
|
@ -114,7 +114,6 @@ rustc_index::newtype_index! {
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
pub struct LiveNode {
|
pub struct LiveNode {
|
||||||
DEBUG_FORMAT = "ln({})",
|
DEBUG_FORMAT = "ln({})",
|
||||||
const INVALID_NODE = LiveNode::MAX_AS_U32,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,12 +167,6 @@ pub fn provide(providers: &mut Providers) {
|
||||||
// variable must not be assigned if there is some successor
|
// variable must not be assigned if there is some successor
|
||||||
// assignment. And so forth.
|
// assignment. And so forth.
|
||||||
|
|
||||||
impl LiveNode {
|
|
||||||
fn is_valid(self) -> bool {
|
|
||||||
self != INVALID_NODE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CaptureInfo {
|
struct CaptureInfo {
|
||||||
ln: LiveNode,
|
ln: LiveNode,
|
||||||
var_hid: HirId,
|
var_hid: HirId,
|
||||||
|
@ -467,8 +460,8 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
struct RWU {
|
struct RWU {
|
||||||
reader: LiveNode,
|
reader: Option<LiveNode>,
|
||||||
writer: LiveNode,
|
writer: Option<LiveNode>,
|
||||||
used: bool,
|
used: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,10 +483,10 @@ struct RWUTable {
|
||||||
unpacked_rwus: Vec<RWU>,
|
unpacked_rwus: Vec<RWU>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A constant representing `RWU { reader: INVALID_NODE; writer: INVALID_NODE; used: false }`.
|
// A constant representing `RWU { reader: None; writer: None; used: false }`.
|
||||||
const INV_INV_FALSE: u32 = u32::MAX;
|
const INV_INV_FALSE: u32 = u32::MAX;
|
||||||
|
|
||||||
// A constant representing `RWU { reader: INVALID_NODE; writer: INVALID_NODE; used: true }`.
|
// A constant representing `RWU { reader: None; writer: None; used: true }`.
|
||||||
const INV_INV_TRUE: u32 = u32::MAX - 1;
|
const INV_INV_TRUE: u32 = u32::MAX - 1;
|
||||||
|
|
||||||
impl RWUTable {
|
impl RWUTable {
|
||||||
|
@ -504,24 +497,24 @@ impl RWUTable {
|
||||||
fn get(&self, idx: usize) -> RWU {
|
fn get(&self, idx: usize) -> RWU {
|
||||||
let packed_rwu = self.packed_rwus[idx];
|
let packed_rwu = self.packed_rwus[idx];
|
||||||
match packed_rwu {
|
match packed_rwu {
|
||||||
INV_INV_FALSE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: false },
|
INV_INV_FALSE => RWU { reader: None, writer: None, used: false },
|
||||||
INV_INV_TRUE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: true },
|
INV_INV_TRUE => RWU { reader: None, writer: None, used: true },
|
||||||
_ => self.unpacked_rwus[packed_rwu as usize],
|
_ => self.unpacked_rwus[packed_rwu as usize],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_reader(&self, idx: usize) -> LiveNode {
|
fn get_reader(&self, idx: usize) -> Option<LiveNode> {
|
||||||
let packed_rwu = self.packed_rwus[idx];
|
let packed_rwu = self.packed_rwus[idx];
|
||||||
match packed_rwu {
|
match packed_rwu {
|
||||||
INV_INV_FALSE | INV_INV_TRUE => INVALID_NODE,
|
INV_INV_FALSE | INV_INV_TRUE => None,
|
||||||
_ => self.unpacked_rwus[packed_rwu as usize].reader,
|
_ => self.unpacked_rwus[packed_rwu as usize].reader,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_writer(&self, idx: usize) -> LiveNode {
|
fn get_writer(&self, idx: usize) -> Option<LiveNode> {
|
||||||
let packed_rwu = self.packed_rwus[idx];
|
let packed_rwu = self.packed_rwus[idx];
|
||||||
match packed_rwu {
|
match packed_rwu {
|
||||||
INV_INV_FALSE | INV_INV_TRUE => INVALID_NODE,
|
INV_INV_FALSE | INV_INV_TRUE => None,
|
||||||
_ => self.unpacked_rwus[packed_rwu as usize].writer,
|
_ => self.unpacked_rwus[packed_rwu as usize].writer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -541,7 +534,7 @@ impl RWUTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_unpacked(&mut self, idx: usize, rwu: RWU) {
|
fn assign_unpacked(&mut self, idx: usize, rwu: RWU) {
|
||||||
if rwu.reader == INVALID_NODE && rwu.writer == INVALID_NODE {
|
if rwu.reader == None && rwu.writer == None {
|
||||||
// When we overwrite an indexing entry in `self.packed_rwus` with
|
// When we overwrite an indexing entry in `self.packed_rwus` with
|
||||||
// `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry
|
// `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry
|
||||||
// from `self.unpacked_rwus`; it's not worth the effort, and we
|
// from `self.unpacked_rwus`; it's not worth the effort, and we
|
||||||
|
@ -570,7 +563,7 @@ struct Liveness<'a, 'tcx> {
|
||||||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
typeck_results: &'a ty::TypeckResults<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
|
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
|
||||||
successors: IndexVec<LiveNode, LiveNode>,
|
successors: IndexVec<LiveNode, Option<LiveNode>>,
|
||||||
rwu_table: RWUTable,
|
rwu_table: RWUTable,
|
||||||
|
|
||||||
/// A live node representing a point of execution before closure entry &
|
/// A live node representing a point of execution before closure entry &
|
||||||
|
@ -606,7 +599,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
typeck_results,
|
typeck_results,
|
||||||
param_env,
|
param_env,
|
||||||
upvars,
|
upvars,
|
||||||
successors: IndexVec::from_elem_n(INVALID_NODE, num_live_nodes),
|
successors: IndexVec::from_elem_n(None, num_live_nodes),
|
||||||
rwu_table: RWUTable::new(num_live_nodes * num_vars),
|
rwu_table: RWUTable::new(num_live_nodes * num_vars),
|
||||||
closure_ln,
|
closure_ln,
|
||||||
exit_ln,
|
exit_ln,
|
||||||
|
@ -651,30 +644,33 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
||||||
assert!(ln.is_valid());
|
if let Some(reader) = self.rwu_table.get_reader(self.idx(ln, var)) {
|
||||||
let reader = self.rwu_table.get_reader(self.idx(ln, var));
|
Some(self.ir.lnks[reader])
|
||||||
if reader.is_valid() { Some(self.ir.lnks[reader]) } else { None }
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this variable live on entry to any of its successor nodes?
|
// Is this variable live on entry to any of its successor nodes?
|
||||||
fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
||||||
let successor = self.successors[ln];
|
let successor = self.successors[ln].unwrap();
|
||||||
self.live_on_entry(successor, var)
|
self.live_on_entry(successor, var)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
|
fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
|
||||||
assert!(ln.is_valid());
|
|
||||||
self.rwu_table.get_used(self.idx(ln, var))
|
self.rwu_table.get_used(self.idx(ln, var))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
||||||
assert!(ln.is_valid());
|
if let Some(writer) = self.rwu_table.get_writer(self.idx(ln, var)) {
|
||||||
let writer = self.rwu_table.get_writer(self.idx(ln, var));
|
Some(self.ir.lnks[writer])
|
||||||
if writer.is_valid() { Some(self.ir.lnks[writer]) } else { None }
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
||||||
let successor = self.successors[ln];
|
let successor = self.successors[ln].unwrap();
|
||||||
self.assigned_on_entry(successor, var)
|
self.assigned_on_entry(successor, var)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,9 +705,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
let wr = &mut wr as &mut dyn Write;
|
let wr = &mut wr as &mut dyn Write;
|
||||||
write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]);
|
write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]);
|
||||||
self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_valid());
|
self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_some());
|
||||||
write!(wr, " writes");
|
write!(wr, " writes");
|
||||||
self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_valid());
|
self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_some());
|
||||||
write!(wr, " uses");
|
write!(wr, " uses");
|
||||||
self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx));
|
self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx));
|
||||||
|
|
||||||
|
@ -735,7 +731,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) {
|
fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) {
|
||||||
self.successors[ln] = succ_ln;
|
self.successors[ln] = Some(succ_ln);
|
||||||
|
|
||||||
// It is not necessary to initialize the RWUs here because they are all
|
// It is not necessary to initialize the RWUs here because they are all
|
||||||
// set to INV_INV_FALSE when they are created, and the sets only grow
|
// set to INV_INV_FALSE when they are created, and the sets only grow
|
||||||
|
@ -744,7 +740,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
|
|
||||||
fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) {
|
fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) {
|
||||||
// more efficient version of init_empty() / merge_from_succ()
|
// more efficient version of init_empty() / merge_from_succ()
|
||||||
self.successors[ln] = succ_ln;
|
self.successors[ln] = Some(succ_ln);
|
||||||
|
|
||||||
self.indices2(ln, succ_ln, |this, idx, succ_idx| {
|
self.indices2(ln, succ_ln, |this, idx, succ_idx| {
|
||||||
this.rwu_table.copy_packed(idx, succ_idx);
|
this.rwu_table.copy_packed(idx, succ_idx);
|
||||||
|
@ -768,12 +764,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
let mut rwu = this.rwu_table.get(idx);
|
let mut rwu = this.rwu_table.get(idx);
|
||||||
let succ_rwu = this.rwu_table.get(succ_idx);
|
let succ_rwu = this.rwu_table.get(succ_idx);
|
||||||
if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() {
|
if succ_rwu.reader.is_some() && rwu.reader.is_none() {
|
||||||
rwu.reader = succ_rwu.reader;
|
rwu.reader = succ_rwu.reader;
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if succ_rwu.writer.is_valid() && !rwu.writer.is_valid() {
|
if succ_rwu.writer.is_some() && rwu.writer.is_none() {
|
||||||
rwu.writer = succ_rwu.writer;
|
rwu.writer = succ_rwu.writer;
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
|
@ -817,14 +813,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
let mut rwu = self.rwu_table.get(idx);
|
let mut rwu = self.rwu_table.get(idx);
|
||||||
|
|
||||||
if (acc & ACC_WRITE) != 0 {
|
if (acc & ACC_WRITE) != 0 {
|
||||||
rwu.reader = INVALID_NODE;
|
rwu.reader = None;
|
||||||
rwu.writer = ln;
|
rwu.writer = Some(ln);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Important: if we both read/write, must do read second
|
// Important: if we both read/write, must do read second
|
||||||
// or else the write will override.
|
// or else the write will override.
|
||||||
if (acc & ACC_READ) != 0 {
|
if (acc & ACC_READ) != 0 {
|
||||||
rwu.reader = ln;
|
rwu.reader = Some(ln);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acc & ACC_USE) != 0 {
|
if (acc & ACC_USE) != 0 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue