liveness: Use Option::None to represent absent live nodes
No functional changes intended.
This commit is contained in:
parent
381b445ff5
commit
93e3db30e9
@ -62,13 +62,13 @@
|
||||
//! - `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 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).
|
||||
//!
|
||||
//! - `writer`: the `LiveNode` ID of some node which will write the
|
||||
//! 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
|
||||
//! `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`.
|
||||
//!
|
||||
//! - `used`: a boolean value indicating whether `V` is *used*. We
|
||||
@ -114,7 +114,6 @@ pub struct Variable {
|
||||
rustc_index::newtype_index! {
|
||||
pub struct LiveNode {
|
||||
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
|
||||
// assignment. And so forth.
|
||||
|
||||
impl LiveNode {
|
||||
fn is_valid(self) -> bool {
|
||||
self != INVALID_NODE
|
||||
}
|
||||
}
|
||||
|
||||
struct CaptureInfo {
|
||||
ln: LiveNode,
|
||||
var_hid: HirId,
|
||||
@ -478,8 +471,8 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct RWU {
|
||||
reader: LiveNode,
|
||||
writer: LiveNode,
|
||||
reader: Option<LiveNode>,
|
||||
writer: Option<LiveNode>,
|
||||
used: bool,
|
||||
}
|
||||
|
||||
@ -501,10 +494,10 @@ struct RWUTable {
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
impl RWUTable {
|
||||
@ -515,24 +508,24 @@ fn new(num_rwus: usize) -> RWUTable {
|
||||
fn get(&self, idx: usize) -> RWU {
|
||||
let packed_rwu = self.packed_rwus[idx];
|
||||
match packed_rwu {
|
||||
INV_INV_FALSE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: false },
|
||||
INV_INV_TRUE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: true },
|
||||
INV_INV_FALSE => RWU { reader: None, writer: None, used: false },
|
||||
INV_INV_TRUE => RWU { reader: None, writer: None, used: true },
|
||||
_ => 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];
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_writer(&self, idx: usize) -> LiveNode {
|
||||
fn get_writer(&self, idx: usize) -> Option<LiveNode> {
|
||||
let packed_rwu = self.packed_rwus[idx];
|
||||
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,
|
||||
}
|
||||
}
|
||||
@ -552,7 +545,7 @@ fn copy_packed(&mut self, dst_idx: usize, src_idx: usize) {
|
||||
}
|
||||
|
||||
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
|
||||
// `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry
|
||||
// from `self.unpacked_rwus`; it's not worth the effort, and we
|
||||
@ -581,7 +574,7 @@ struct Liveness<'a, 'tcx> {
|
||||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
|
||||
successors: IndexVec<LiveNode, LiveNode>,
|
||||
successors: IndexVec<LiveNode, Option<LiveNode>>,
|
||||
rwu_table: RWUTable,
|
||||
|
||||
/// A live node representing a point of execution before closure entry &
|
||||
@ -617,7 +610,7 @@ fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> {
|
||||
typeck_results,
|
||||
param_env,
|
||||
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),
|
||||
closure_ln,
|
||||
exit_ln,
|
||||
@ -662,30 +655,33 @@ fn idx(&self, ln: LiveNode, var: Variable) -> usize {
|
||||
}
|
||||
|
||||
fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
||||
assert!(ln.is_valid());
|
||||
let reader = self.rwu_table.get_reader(self.idx(ln, var));
|
||||
if reader.is_valid() { Some(self.ir.lnks[reader]) } else { None }
|
||||
if let Some(reader) = self.rwu_table.get_reader(self.idx(ln, var)) {
|
||||
Some(self.ir.lnks[reader])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Is this variable live on entry to any of its successor nodes?
|
||||
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)
|
||||
}
|
||||
|
||||
fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
|
||||
assert!(ln.is_valid());
|
||||
self.rwu_table.get_used(self.idx(ln, var))
|
||||
}
|
||||
|
||||
fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
|
||||
assert!(ln.is_valid());
|
||||
let writer = self.rwu_table.get_writer(self.idx(ln, var));
|
||||
if writer.is_valid() { Some(self.ir.lnks[writer]) } else { None }
|
||||
if let Some(writer) = self.rwu_table.get_writer(self.idx(ln, var)) {
|
||||
Some(self.ir.lnks[writer])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -720,9 +716,9 @@ fn ln_str(&self, ln: LiveNode) -> String {
|
||||
{
|
||||
let wr = &mut wr as &mut dyn Write;
|
||||
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");
|
||||
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");
|
||||
self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx));
|
||||
|
||||
@ -746,7 +742,7 @@ fn log_liveness(&self, entry_ln: LiveNode, hir_id: hir::HirId) {
|
||||
}
|
||||
|
||||
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
|
||||
// set to INV_INV_FALSE when they are created, and the sets only grow
|
||||
@ -755,7 +751,7 @@ fn init_empty(&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()
|
||||
self.successors[ln] = succ_ln;
|
||||
self.successors[ln] = Some(succ_ln);
|
||||
|
||||
self.indices2(ln, succ_ln, |this, idx, succ_idx| {
|
||||
this.rwu_table.copy_packed(idx, succ_idx);
|
||||
@ -779,12 +775,12 @@ fn merge_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode, first_merge: bool
|
||||
let mut changed = false;
|
||||
let mut rwu = this.rwu_table.get(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;
|
||||
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;
|
||||
changed = true
|
||||
}
|
||||
@ -828,14 +824,14 @@ fn acc(&mut self, ln: LiveNode, var: Variable, acc: u32) {
|
||||
let mut rwu = self.rwu_table.get(idx);
|
||||
|
||||
if (acc & ACC_WRITE) != 0 {
|
||||
rwu.reader = INVALID_NODE;
|
||||
rwu.writer = ln;
|
||||
rwu.reader = None;
|
||||
rwu.writer = Some(ln);
|
||||
}
|
||||
|
||||
// Important: if we both read/write, must do read second
|
||||
// or else the write will override.
|
||||
if (acc & ACC_READ) != 0 {
|
||||
rwu.reader = ln;
|
||||
rwu.reader = Some(ln);
|
||||
}
|
||||
|
||||
if (acc & ACC_USE) != 0 {
|
||||
|
Loading…
Reference in New Issue
Block a user