Skip to content

Commit b867d13

Browse files
authored
Rollup merge of #79844 - tmiasko:rwu-table-mod, r=lcnr
Move RWUTable to a separate module
2 parents 9ced8dc + c7d7bc9 commit b867d13

File tree

2 files changed

+149
-146
lines changed

2 files changed

+149
-146
lines changed

compiler/rustc_passes/src/liveness.rs

+5-146
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ use std::io;
105105
use std::io::prelude::*;
106106
use std::rc::Rc;
107107

108+
mod rwu_table;
109+
108110
rustc_index::newtype_index! {
109111
pub struct Variable {
110112
DEBUG_FORMAT = "v({})",
@@ -468,149 +470,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
468470
// Actually we compute just a bit more than just liveness, but we use
469471
// the same basic propagation framework in all cases.
470472

471-
#[derive(Clone, Copy)]
472-
struct RWU {
473-
reader: bool,
474-
writer: bool,
475-
used: bool,
476-
}
477-
478-
/// Conceptually, this is like a `Vec<Vec<RWU>>`. But the number of
479-
/// RWU`s can get very large, so it uses a more compact representation.
480-
struct RWUTable {
481-
/// Total number of live nodes.
482-
live_nodes: usize,
483-
/// Total number of variables.
484-
vars: usize,
485-
486-
/// A compressed representation of `RWU`s.
487-
///
488-
/// Each word represents 2 different `RWU`s packed together. Each packed RWU
489-
/// is stored in 4 bits: a reader bit, a writer bit, a used bit and a
490-
/// padding bit.
491-
///
492-
/// The data for each live node is contiguous and starts at a word boundary,
493-
/// so there might be an unused space left.
494-
words: Vec<u8>,
495-
/// Number of words per each live node.
496-
live_node_words: usize,
497-
}
498-
499-
impl RWUTable {
500-
const RWU_READER: u8 = 0b0001;
501-
const RWU_WRITER: u8 = 0b0010;
502-
const RWU_USED: u8 = 0b0100;
503-
const RWU_MASK: u8 = 0b1111;
504-
505-
/// Size of packed RWU in bits.
506-
const RWU_BITS: usize = 4;
507-
/// Size of a word in bits.
508-
const WORD_BITS: usize = std::mem::size_of::<u8>() * 8;
509-
/// Number of packed RWUs that fit into a single word.
510-
const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS;
511-
512-
fn new(live_nodes: usize, vars: usize) -> RWUTable {
513-
let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT;
514-
Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] }
515-
}
516-
517-
fn word_and_shift(&self, ln: LiveNode, var: Variable) -> (usize, u32) {
518-
assert!(ln.index() < self.live_nodes);
519-
assert!(var.index() < self.vars);
520-
521-
let var = var.index();
522-
let word = var / Self::WORD_RWU_COUNT;
523-
let shift = Self::RWU_BITS * (var % Self::WORD_RWU_COUNT);
524-
(ln.index() * self.live_node_words + word, shift as u32)
525-
}
526-
527-
fn pick2_rows_mut(&mut self, a: LiveNode, b: LiveNode) -> (&mut [u8], &mut [u8]) {
528-
assert!(a.index() < self.live_nodes);
529-
assert!(b.index() < self.live_nodes);
530-
assert!(a != b);
531-
532-
let a_start = a.index() * self.live_node_words;
533-
let b_start = b.index() * self.live_node_words;
534-
535-
unsafe {
536-
let ptr = self.words.as_mut_ptr();
537-
(
538-
std::slice::from_raw_parts_mut(ptr.add(a_start), self.live_node_words),
539-
std::slice::from_raw_parts_mut(ptr.add(b_start), self.live_node_words),
540-
)
541-
}
542-
}
543-
544-
fn copy(&mut self, dst: LiveNode, src: LiveNode) {
545-
if dst == src {
546-
return;
547-
}
548-
549-
let (dst_row, src_row) = self.pick2_rows_mut(dst, src);
550-
dst_row.copy_from_slice(src_row);
551-
}
552-
553-
/// Sets `dst` to the union of `dst` and `src`, returns true if `dst` was
554-
/// changed.
555-
fn union(&mut self, dst: LiveNode, src: LiveNode) -> bool {
556-
if dst == src {
557-
return false;
558-
}
559-
560-
let mut changed = false;
561-
let (dst_row, src_row) = self.pick2_rows_mut(dst, src);
562-
for (dst_word, src_word) in dst_row.iter_mut().zip(src_row.iter()) {
563-
let old = *dst_word;
564-
let new = *dst_word | src_word;
565-
*dst_word = new;
566-
changed |= old != new;
567-
}
568-
changed
569-
}
570-
571-
fn get_reader(&self, ln: LiveNode, var: Variable) -> bool {
572-
let (word, shift) = self.word_and_shift(ln, var);
573-
(self.words[word] >> shift) & Self::RWU_READER != 0
574-
}
575-
576-
fn get_writer(&self, ln: LiveNode, var: Variable) -> bool {
577-
let (word, shift) = self.word_and_shift(ln, var);
578-
(self.words[word] >> shift) & Self::RWU_WRITER != 0
579-
}
580-
581-
fn get_used(&self, ln: LiveNode, var: Variable) -> bool {
582-
let (word, shift) = self.word_and_shift(ln, var);
583-
(self.words[word] >> shift) & Self::RWU_USED != 0
584-
}
585-
586-
fn get(&self, ln: LiveNode, var: Variable) -> RWU {
587-
let (word, shift) = self.word_and_shift(ln, var);
588-
let rwu_packed = self.words[word] >> shift;
589-
RWU {
590-
reader: rwu_packed & Self::RWU_READER != 0,
591-
writer: rwu_packed & Self::RWU_WRITER != 0,
592-
used: rwu_packed & Self::RWU_USED != 0,
593-
}
594-
}
595-
596-
fn set(&mut self, ln: LiveNode, var: Variable, rwu: RWU) {
597-
let mut packed = 0;
598-
if rwu.reader {
599-
packed |= Self::RWU_READER;
600-
}
601-
if rwu.writer {
602-
packed |= Self::RWU_WRITER;
603-
}
604-
if rwu.used {
605-
packed |= Self::RWU_USED;
606-
}
607-
608-
let (word, shift) = self.word_and_shift(ln, var);
609-
let word = &mut self.words[word];
610-
*word = (*word & !(Self::RWU_MASK << shift)) | (packed << shift)
611-
}
612-
}
613-
614473
const ACC_READ: u32 = 1;
615474
const ACC_WRITE: u32 = 2;
616475
const ACC_USE: u32 = 4;
@@ -623,7 +482,7 @@ struct Liveness<'a, 'tcx> {
623482
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
624483
closure_captures: Option<&'tcx FxIndexMap<hir::HirId, ty::UpvarId>>,
625484
successors: IndexVec<LiveNode, Option<LiveNode>>,
626-
rwu_table: RWUTable,
485+
rwu_table: rwu_table::RWUTable,
627486

628487
/// A live node representing a point of execution before closure entry &
629488
/// after closure exit. Used to calculate liveness of captured variables
@@ -661,7 +520,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
661520
upvars,
662521
closure_captures,
663522
successors: IndexVec::from_elem_n(None, num_live_nodes),
664-
rwu_table: RWUTable::new(num_live_nodes, num_vars),
523+
rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars),
665524
closure_ln,
666525
exit_ln,
667526
break_ln: Default::default(),
@@ -796,7 +655,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
796655
// this) so we just clear out all the data.
797656
fn define(&mut self, writer: LiveNode, var: Variable) {
798657
let used = self.rwu_table.get_used(writer, var);
799-
self.rwu_table.set(writer, var, RWU { reader: false, writer: false, used });
658+
self.rwu_table.set(writer, var, rwu_table::RWU { reader: false, writer: false, used });
800659
debug!("{:?} defines {:?}: {}", writer, var, self.ln_str(writer));
801660
}
802661

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
use crate::liveness::{LiveNode, Variable};
2+
3+
#[derive(Clone, Copy)]
4+
pub(super) struct RWU {
5+
pub(super) reader: bool,
6+
pub(super) writer: bool,
7+
pub(super) used: bool,
8+
}
9+
10+
/// Conceptually, this is like a `Vec<Vec<RWU>>`. But the number of
11+
/// RWU`s can get very large, so it uses a more compact representation.
12+
pub(super) struct RWUTable {
13+
/// Total number of live nodes.
14+
live_nodes: usize,
15+
/// Total number of variables.
16+
vars: usize,
17+
18+
/// A compressed representation of `RWU`s.
19+
///
20+
/// Each word represents 2 different `RWU`s packed together. Each packed RWU
21+
/// is stored in 4 bits: a reader bit, a writer bit, a used bit and a
22+
/// padding bit.
23+
///
24+
/// The data for each live node is contiguous and starts at a word boundary,
25+
/// so there might be an unused space left.
26+
words: Vec<u8>,
27+
/// Number of words per each live node.
28+
live_node_words: usize,
29+
}
30+
31+
impl RWUTable {
32+
const RWU_READER: u8 = 0b0001;
33+
const RWU_WRITER: u8 = 0b0010;
34+
const RWU_USED: u8 = 0b0100;
35+
const RWU_MASK: u8 = 0b1111;
36+
37+
/// Size of packed RWU in bits.
38+
const RWU_BITS: usize = 4;
39+
/// Size of a word in bits.
40+
const WORD_BITS: usize = std::mem::size_of::<u8>() * 8;
41+
/// Number of packed RWUs that fit into a single word.
42+
const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS;
43+
44+
pub(super) fn new(live_nodes: usize, vars: usize) -> RWUTable {
45+
let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT;
46+
Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] }
47+
}
48+
49+
fn word_and_shift(&self, ln: LiveNode, var: Variable) -> (usize, u32) {
50+
assert!(ln.index() < self.live_nodes);
51+
assert!(var.index() < self.vars);
52+
53+
let var = var.index();
54+
let word = var / Self::WORD_RWU_COUNT;
55+
let shift = Self::RWU_BITS * (var % Self::WORD_RWU_COUNT);
56+
(ln.index() * self.live_node_words + word, shift as u32)
57+
}
58+
59+
fn pick2_rows_mut(&mut self, a: LiveNode, b: LiveNode) -> (&mut [u8], &mut [u8]) {
60+
assert!(a.index() < self.live_nodes);
61+
assert!(b.index() < self.live_nodes);
62+
assert!(a != b);
63+
64+
let a_start = a.index() * self.live_node_words;
65+
let b_start = b.index() * self.live_node_words;
66+
67+
unsafe {
68+
let ptr = self.words.as_mut_ptr();
69+
(
70+
std::slice::from_raw_parts_mut(ptr.add(a_start), self.live_node_words),
71+
std::slice::from_raw_parts_mut(ptr.add(b_start), self.live_node_words),
72+
)
73+
}
74+
}
75+
76+
pub(super) fn copy(&mut self, dst: LiveNode, src: LiveNode) {
77+
if dst == src {
78+
return;
79+
}
80+
81+
let (dst_row, src_row) = self.pick2_rows_mut(dst, src);
82+
dst_row.copy_from_slice(src_row);
83+
}
84+
85+
/// Sets `dst` to the union of `dst` and `src`, returns true if `dst` was
86+
/// changed.
87+
pub(super) fn union(&mut self, dst: LiveNode, src: LiveNode) -> bool {
88+
if dst == src {
89+
return false;
90+
}
91+
92+
let mut changed = false;
93+
let (dst_row, src_row) = self.pick2_rows_mut(dst, src);
94+
for (dst_word, src_word) in dst_row.iter_mut().zip(src_row.iter()) {
95+
let old = *dst_word;
96+
let new = *dst_word | src_word;
97+
*dst_word = new;
98+
changed |= old != new;
99+
}
100+
changed
101+
}
102+
103+
pub(super) fn get_reader(&self, ln: LiveNode, var: Variable) -> bool {
104+
let (word, shift) = self.word_and_shift(ln, var);
105+
(self.words[word] >> shift) & Self::RWU_READER != 0
106+
}
107+
108+
pub(super) fn get_writer(&self, ln: LiveNode, var: Variable) -> bool {
109+
let (word, shift) = self.word_and_shift(ln, var);
110+
(self.words[word] >> shift) & Self::RWU_WRITER != 0
111+
}
112+
113+
pub(super) fn get_used(&self, ln: LiveNode, var: Variable) -> bool {
114+
let (word, shift) = self.word_and_shift(ln, var);
115+
(self.words[word] >> shift) & Self::RWU_USED != 0
116+
}
117+
118+
pub(super) fn get(&self, ln: LiveNode, var: Variable) -> RWU {
119+
let (word, shift) = self.word_and_shift(ln, var);
120+
let rwu_packed = self.words[word] >> shift;
121+
RWU {
122+
reader: rwu_packed & Self::RWU_READER != 0,
123+
writer: rwu_packed & Self::RWU_WRITER != 0,
124+
used: rwu_packed & Self::RWU_USED != 0,
125+
}
126+
}
127+
128+
pub(super) fn set(&mut self, ln: LiveNode, var: Variable, rwu: RWU) {
129+
let mut packed = 0;
130+
if rwu.reader {
131+
packed |= Self::RWU_READER;
132+
}
133+
if rwu.writer {
134+
packed |= Self::RWU_WRITER;
135+
}
136+
if rwu.used {
137+
packed |= Self::RWU_USED;
138+
}
139+
140+
let (word, shift) = self.word_and_shift(ln, var);
141+
let word = &mut self.words[word];
142+
*word = (*word & !(Self::RWU_MASK << shift)) | (packed << shift)
143+
}
144+
}

0 commit comments

Comments
 (0)