Skip to content

Commit bc2c073

Browse files
committedSep 13, 2021
Duplicate liveness code for generator liveness analysis
1 parent e49e5b9 commit bc2c073

File tree

4 files changed

+1025
-53
lines changed

4 files changed

+1025
-53
lines changed
 

‎compiler/rustc_passes/src/liveness.rs

+21-15
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ use std::io::prelude::*;
106106
use std::iter;
107107
use std::rc::Rc;
108108

109-
mod rwu_table;
109+
pub mod rwu_table;
110110

111111
rustc_index::newtype_index! {
112112
pub struct Variable {
@@ -121,7 +121,7 @@ rustc_index::newtype_index! {
121121
}
122122

123123
#[derive(Copy, Clone, PartialEq, Debug)]
124-
enum LiveNodeKind {
124+
pub enum LiveNodeKind {
125125
UpvarNode(Span),
126126
ExprNode(Span, HirId),
127127
VarDefNode(Span, HirId),
@@ -170,9 +170,9 @@ pub fn provide(providers: &mut Providers) {
170170
// variable must not be assigned if there is some successor
171171
// assignment. And so forth.
172172

173-
struct CaptureInfo {
174-
ln: LiveNode,
175-
var_hid: HirId,
173+
pub struct CaptureInfo {
174+
pub ln: LiveNode,
175+
pub var_hid: HirId,
176176
}
177177

178178
#[derive(Copy, Clone, Debug)]
@@ -194,16 +194,16 @@ pub enum VarKind {
194194
}
195195

196196
pub struct IrMaps<'tcx> {
197-
tcx: TyCtxt<'tcx>,
198-
live_node_map: HirIdMap<LiveNode>,
199-
variable_map: HirIdMap<Variable>,
200-
capture_info_map: HirIdMap<Rc<Vec<CaptureInfo>>>,
201-
var_kinds: IndexVec<Variable, VarKind>,
202-
lnks: IndexVec<LiveNode, LiveNodeKind>,
197+
pub tcx: TyCtxt<'tcx>,
198+
pub live_node_map: HirIdMap<LiveNode>,
199+
pub variable_map: HirIdMap<Variable>,
200+
pub capture_info_map: HirIdMap<Rc<Vec<CaptureInfo>>>,
201+
pub var_kinds: IndexVec<Variable, VarKind>,
202+
pub lnks: IndexVec<LiveNode, LiveNodeKind>,
203203
}
204204

205205
impl IrMaps<'tcx> {
206-
fn new(tcx: TyCtxt<'tcx>) -> IrMaps<'tcx> {
206+
pub fn new(tcx: TyCtxt<'tcx>) -> IrMaps<'tcx> {
207207
IrMaps {
208208
tcx,
209209
live_node_map: HirIdMap::default(),
@@ -214,7 +214,7 @@ impl IrMaps<'tcx> {
214214
}
215215
}
216216

217-
fn add_live_node(&mut self, lnk: LiveNodeKind) -> LiveNode {
217+
pub fn add_live_node(&mut self, lnk: LiveNodeKind) -> LiveNode {
218218
let ln = self.lnks.push(lnk);
219219

220220
debug!("{:?} is of kind {}", ln, live_node_kind_to_string(lnk, self.tcx));
@@ -246,7 +246,7 @@ impl IrMaps<'tcx> {
246246
v
247247
}
248248

249-
fn variable(&self, hir_id: HirId, span: Span) -> Variable {
249+
pub fn variable(&self, hir_id: HirId, span: Span) -> Variable {
250250
match self.variable_map.get(&hir_id) {
251251
Some(&var) => var,
252252
None => {
@@ -255,13 +255,19 @@ impl IrMaps<'tcx> {
255255
}
256256
}
257257

258-
fn variable_name(&self, var: Variable) -> Symbol {
258+
pub fn variable_name(&self, var: Variable) -> Symbol {
259259
match self.var_kinds[var] {
260260
Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name,
261261
Temporary(..) => Symbol::intern("[temporary]"),
262262
}
263263
}
264264

265+
pub fn variable_hir_id(&self, var: Variable) -> HirId {
266+
match self.var_kinds[var] {
267+
Local(LocalInfo { id, .. }) | Param(id, ..) | Upvar(id, ..) | Temporary(id) => id,
268+
}
269+
}
270+
265271
fn variable_is_shorthand(&self, var: Variable) -> bool {
266272
match self.var_kinds[var] {
267273
Local(LocalInfo { is_shorthand, .. }) => is_shorthand,

‎compiler/rustc_passes/src/liveness/rwu_table.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ use crate::liveness::{LiveNode, Variable};
22
use std::iter;
33

44
#[derive(Clone, Copy)]
5-
pub(super) struct RWU {
6-
pub(super) reader: bool,
7-
pub(super) writer: bool,
8-
pub(super) used: bool,
5+
pub struct RWU {
6+
pub reader: bool,
7+
pub writer: bool,
8+
pub used: bool,
99
}
1010

1111
/// Conceptually, this is like a `Vec<Vec<RWU>>`. But the number of
1212
/// RWU`s can get very large, so it uses a more compact representation.
13-
pub(super) struct RWUTable {
13+
pub struct RWUTable {
1414
/// Total number of live nodes.
1515
live_nodes: usize,
1616
/// Total number of variables.
@@ -42,7 +42,7 @@ impl RWUTable {
4242
/// Number of packed RWUs that fit into a single word.
4343
const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS;
4444

45-
pub(super) fn new(live_nodes: usize, vars: usize) -> RWUTable {
45+
pub fn new(live_nodes: usize, vars: usize) -> RWUTable {
4646
let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT;
4747
Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] }
4848
}
@@ -74,7 +74,7 @@ impl RWUTable {
7474
}
7575
}
7676

77-
pub(super) fn copy(&mut self, dst: LiveNode, src: LiveNode) {
77+
pub fn copy(&mut self, dst: LiveNode, src: LiveNode) {
7878
if dst == src {
7979
return;
8080
}
@@ -85,7 +85,7 @@ impl RWUTable {
8585

8686
/// Sets `dst` to the union of `dst` and `src`, returns true if `dst` was
8787
/// changed.
88-
pub(super) fn union(&mut self, dst: LiveNode, src: LiveNode) -> bool {
88+
pub fn union(&mut self, dst: LiveNode, src: LiveNode) -> bool {
8989
if dst == src {
9090
return false;
9191
}
@@ -101,22 +101,22 @@ impl RWUTable {
101101
changed
102102
}
103103

104-
pub(super) fn get_reader(&self, ln: LiveNode, var: Variable) -> bool {
104+
pub fn get_reader(&self, ln: LiveNode, var: Variable) -> bool {
105105
let (word, shift) = self.word_and_shift(ln, var);
106106
(self.words[word] >> shift) & Self::RWU_READER != 0
107107
}
108108

109-
pub(super) fn get_writer(&self, ln: LiveNode, var: Variable) -> bool {
109+
pub fn get_writer(&self, ln: LiveNode, var: Variable) -> bool {
110110
let (word, shift) = self.word_and_shift(ln, var);
111111
(self.words[word] >> shift) & Self::RWU_WRITER != 0
112112
}
113113

114-
pub(super) fn get_used(&self, ln: LiveNode, var: Variable) -> bool {
114+
pub fn get_used(&self, ln: LiveNode, var: Variable) -> bool {
115115
let (word, shift) = self.word_and_shift(ln, var);
116116
(self.words[word] >> shift) & Self::RWU_USED != 0
117117
}
118118

119-
pub(super) fn get(&self, ln: LiveNode, var: Variable) -> RWU {
119+
pub fn get(&self, ln: LiveNode, var: Variable) -> RWU {
120120
let (word, shift) = self.word_and_shift(ln, var);
121121
let rwu_packed = self.words[word] >> shift;
122122
RWU {
@@ -126,7 +126,7 @@ impl RWUTable {
126126
}
127127
}
128128

129-
pub(super) fn set(&mut self, ln: LiveNode, var: Variable, rwu: RWU) {
129+
pub fn set(&mut self, ln: LiveNode, var: Variable, rwu: RWU) {
130130
let mut packed = 0;
131131
if rwu.reader {
132132
packed |= Self::RWU_READER;

‎compiler/rustc_typeck/src/check/generator_interior.rs

+221-24
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
//! This calculates the types which has storage which lives across a suspension point in a
22
//! generator from the perspective of typeck. The actual types used at runtime
3-
//! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the
3+
//! is calculated in `rustc_mir::transform::generator` and may be a subset of the
44
//! types computed here.
55
6+
// use crate::expr_use_visitor::{self, ExprUseVisitor};
7+
8+
use crate::expr_use_visitor::{self, ExprUseVisitor};
9+
10+
use super::generator_liveness::Liveness;
611
use super::FnCtxt;
7-
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
12+
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
813
use rustc_hir as hir;
914
use rustc_hir::def::{CtorKind, DefKind, Res};
1015
use rustc_hir::def_id::DefId;
1116
use rustc_hir::hir_id::HirIdSet;
1217
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
1318
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
19+
use rustc_infer::infer::RegionVariableOrigin;
1420
use rustc_middle::middle::region::{self, YieldData};
15-
use rustc_middle::ty::{self, Ty};
21+
use rustc_middle::ty::{self, BorrowKind, Ty, TypeckResults};
22+
use rustc_passes::liveness::{self, IrMaps, Variable};
1623
use rustc_span::Span;
1724
use smallvec::SmallVec;
1825

19-
struct InteriorVisitor<'a, 'tcx> {
26+
struct InteriorVisitor<'a, 'atcx, 'tcx> {
2027
fcx: &'a FnCtxt<'a, 'tcx>,
2128
types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
2229
region_scope_tree: &'tcx region::ScopeTree,
@@ -30,9 +37,11 @@ struct InteriorVisitor<'a, 'tcx> {
3037
/// that they may succeed the said yield point in the post-order.
3138
guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
3239
guard_bindings_set: HirIdSet,
40+
liveness: Liveness<'a, 'atcx, 'tcx>,
41+
live_across_yield: FxIndexSet<Variable>,
3342
}
3443

35-
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
44+
impl<'a, 'atcx, 'tcx> InteriorVisitor<'a, 'atcx, 'tcx> {
3645
fn record(
3746
&mut self,
3847
ty: Ty<'tcx>,
@@ -154,24 +163,72 @@ pub fn resolve_interior<'a, 'tcx>(
154163
kind: hir::GeneratorKind,
155164
) {
156165
let body = fcx.tcx.hir().body(body_id);
157-
let mut visitor = InteriorVisitor {
158-
fcx,
159-
types: FxIndexSet::default(),
160-
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
161-
expr_count: 0,
162-
kind,
163-
prev_unresolved_span: None,
164-
guard_bindings: <_>::default(),
165-
guard_bindings_set: <_>::default(),
166-
};
167-
intravisit::walk_body(&mut visitor, body);
168-
169-
// Check that we visited the same amount of expressions and the RegionResolutionVisitor
170-
let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
171-
assert_eq!(region_expr_count, visitor.expr_count);
166+
let types = {
167+
let mut ir_maps = IrMaps::new(fcx.tcx);
168+
// FIXME: use this to inform capture information
169+
let typeck_results = fcx.inh.typeck_results.borrow();
170+
let liveness = compute_body_liveness(&fcx, &mut ir_maps, body_id, &typeck_results);
171+
let mut visitor = InteriorVisitor {
172+
fcx,
173+
types: FxIndexSet::default(),
174+
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
175+
expr_count: 0,
176+
kind,
177+
prev_unresolved_span: None,
178+
guard_bindings: <_>::default(),
179+
guard_bindings_set: <_>::default(),
180+
liveness: liveness.liveness,
181+
live_across_yield: FxIndexSet::default(),
182+
};
183+
intravisit::walk_body(&mut visitor, body);
184+
185+
// Check that we visited the same amount of expressions and the RegionResolutionVisitor
186+
let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
187+
assert_eq!(region_expr_count, visitor.expr_count);
188+
189+
// The types are already kept in insertion order.
190+
// let types = visitor.types;
191+
let borrows = liveness.borrows;
192+
let mut types = visitor
193+
.live_across_yield
194+
.iter()
195+
.map(|v| {
196+
let var_hir_id = visitor.liveness.ir.variable_hir_id(*v);
197+
let ty = visitor.fcx.inh.typeck_results.borrow().node_type(var_hir_id);
198+
199+
// fixup type if it is borrowed
200+
let ty = if let Some(bk) = borrows.get(&var_hir_id) {
201+
// FIXME: this is almost certainly the wrong origin to use here.
202+
let origin = RegionVariableOrigin::AddrOfRegion(fcx.tcx.hir().span(var_hir_id));
203+
let region = fcx.infcx.next_region_var(origin);
204+
match bk {
205+
BorrowKind::ImmBorrow | BorrowKind::UniqueImmBorrow => {
206+
visitor.fcx.tcx.mk_imm_ref(region, ty)
207+
}
208+
BorrowKind::MutBorrow => visitor.fcx.tcx.mk_mut_ref(region, ty),
209+
}
210+
} else {
211+
ty
212+
};
213+
214+
ty::GeneratorInteriorTypeCause {
215+
ty,
216+
span: fcx.tcx.hir().span(var_hir_id),
217+
scope_span: None,
218+
yield_span: fcx.tcx.hir().span(var_hir_id), // FIXME: this should be the yield span instead
219+
expr: None,
220+
}
221+
})
222+
.collect::<FxIndexSet<_>>();
172223

173-
// The types are already kept in insertion order.
174-
let types = visitor.types;
224+
// Now add in any temporaries that implement Drop
225+
for ty in visitor.types.drain(..) {
226+
if ty.ty.has_significant_drop(fcx.tcx, fcx.param_env) {
227+
types.insert(ty);
228+
}
229+
}
230+
types
231+
};
175232

176233
// The types in the generator interior contain lifetimes local to the generator itself,
177234
// which should not be exposed outside of the generator. Therefore, we replace these
@@ -224,7 +281,7 @@ pub fn resolve_interior<'a, 'tcx>(
224281
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
225282

226283
// Store the generator types and spans into the typeck results for this generator.
227-
visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types =
284+
fcx.inh.typeck_results.borrow_mut().generator_interior_types =
228285
ty::Binder::bind_with_vars(type_causes, bound_vars);
229286

230287
debug!(
@@ -242,7 +299,7 @@ pub fn resolve_interior<'a, 'tcx>(
242299
// This visitor has to have the same visit_expr calls as RegionResolutionVisitor in
243300
// librustc_middle/middle/region.rs since `expr_count` is compared against the results
244301
// there.
245-
impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
302+
impl<'a, 'atcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'atcx, 'tcx> {
246303
type Map = intravisit::ErasedMap<'tcx>;
247304

248305
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -332,6 +389,30 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
332389
_ => {}
333390
}
334391
}
392+
ExprKind::Yield(..) => {
393+
let live_node = self.liveness.live_node(expr.hir_id, expr.span);
394+
395+
debug!("***Dumping variable liveness information***");
396+
for (_, &var) in self.liveness.ir.variable_map.iter() {
397+
if self.liveness.live_on_entry(live_node, var) {
398+
debug!(
399+
" Variable {:?}: {:?} (ty={:?}) is live on entry at {:?}",
400+
var,
401+
self.liveness.ir.variable_name(var),
402+
self.fcx
403+
.typeck_results
404+
.borrow()
405+
.node_type(self.liveness.ir.variable_hir_id(var)),
406+
expr.span
407+
);
408+
409+
self.live_across_yield.insert(var);
410+
}
411+
}
412+
debug!("***Done dumping variable liveness information***");
413+
414+
intravisit::walk_expr(self, expr);
415+
}
335416
_ => intravisit::walk_expr(self, expr),
336417
}
337418

@@ -409,3 +490,119 @@ impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
409490
}
410491
}
411492
}
493+
494+
struct GeneratorLiveness<'a, 'atcx, 'tcx> {
495+
liveness: Liveness<'a, 'atcx, 'tcx>,
496+
borrows: FxIndexMap<HirId, BorrowKind>,
497+
}
498+
499+
// Expose liveness computation to other passes that might need it.
500+
fn compute_body_liveness(
501+
fcx: &FnCtxt<'a, 'tcx>,
502+
maps: &'a mut IrMaps<'tcx>,
503+
body_id: hir::BodyId,
504+
typeck_results: &'atcx TypeckResults<'tcx>,
505+
) -> GeneratorLiveness<'a, 'atcx, 'tcx>
506+
where
507+
'atcx: 'a,
508+
{
509+
let body = fcx.tcx.hir().body(body_id);
510+
let body_owner = fcx.tcx.hir().body_owner(body_id);
511+
let body_owner_local_def_id = fcx.tcx.hir().local_def_id(body_owner);
512+
513+
if let Some(captures) =
514+
typeck_results.closure_min_captures.get(&body_owner_local_def_id.to_def_id())
515+
{
516+
for &var_hir_id in captures.keys() {
517+
let var_name = fcx.tcx.hir().name(var_hir_id);
518+
maps.add_variable(liveness::VarKind::Upvar(var_hir_id, var_name));
519+
}
520+
}
521+
522+
let mut borrows = <_>::default();
523+
524+
// gather up the various local variables, significant expressions,
525+
// and so forth:
526+
intravisit::walk_body(maps, body);
527+
ExprUseVisitor::new(
528+
&mut ExprUseDelegate {
529+
hir: &fcx.tcx.hir(),
530+
_maps: maps,
531+
typeck_results: &fcx.typeck_results.borrow(),
532+
borrows: &mut borrows,
533+
},
534+
&fcx.infcx,
535+
body_owner_local_def_id,
536+
fcx.param_env,
537+
typeck_results,
538+
)
539+
.consume_body(body);
540+
541+
// compute liveness
542+
let mut lsets = Liveness::new(maps, body_owner_local_def_id, typeck_results);
543+
lsets.compute(&body, body_owner);
544+
545+
GeneratorLiveness { liveness: lsets, borrows }
546+
}
547+
548+
/// We use ExprUseVisitor to gather up all the temporary values whose liveness we need to consider.
549+
struct ExprUseDelegate<'a, 'tcx> {
550+
hir: &'a rustc_middle::hir::map::Map<'tcx>,
551+
_maps: &'a mut IrMaps<'tcx>,
552+
typeck_results: &'a TypeckResults<'tcx>,
553+
borrows: &'a mut FxIndexMap<HirId, BorrowKind>,
554+
}
555+
556+
impl<'a, 'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'a, 'tcx> {
557+
fn consume(
558+
&mut self,
559+
place_with_id: &rustc_middle::hir::place::PlaceWithHirId<'tcx>,
560+
_diag_expr_id: hir::HirId,
561+
) {
562+
debug!(
563+
"ExprUseDelegate: consume {} ty={:?}, {:?}",
564+
place_with_id.hir_id,
565+
self.typeck_results.node_type(place_with_id.hir_id),
566+
self.hir.span(place_with_id.hir_id)
567+
);
568+
// self.maps.add_variable(liveness::VarKind::Temporary(place_with_id.hir_id));
569+
}
570+
571+
fn borrow(
572+
&mut self,
573+
place_with_id: &rustc_middle::hir::place::PlaceWithHirId<'tcx>,
574+
_diag_expr_id: hir::HirId,
575+
bk: BorrowKind,
576+
) {
577+
debug!(
578+
"ExprUseDelegate: borrow {} ty={:?}, {:?}",
579+
place_with_id.hir_id,
580+
self.typeck_results.node_type(place_with_id.hir_id),
581+
self.hir.span(place_with_id.hir_id)
582+
);
583+
self.borrows.insert(place_with_id.hir_id, bk);
584+
// self.maps.add_variable(liveness::VarKind::Temporary(place_with_id.hir_id));
585+
}
586+
587+
fn mutate(
588+
&mut self,
589+
assignee_place: &rustc_middle::hir::place::PlaceWithHirId<'tcx>,
590+
_diag_expr_id: hir::HirId,
591+
) {
592+
debug!(
593+
"ExprUseDelegate: mutate {} ty={:?}, {:?}",
594+
assignee_place.hir_id,
595+
self.typeck_results.node_type(assignee_place.hir_id),
596+
self.hir.span(assignee_place.hir_id)
597+
);
598+
// self.maps.add_variable(liveness::VarKind::Temporary(assignee_place.hir_id));
599+
}
600+
601+
fn fake_read(
602+
&mut self,
603+
_place: rustc_middle::hir::place::Place<'tcx>,
604+
_cause: rustc_middle::mir::FakeReadCause,
605+
_diag_expr_id: hir::HirId,
606+
) {
607+
}
608+
}

‎compiler/rustc_typeck/src/check/generator_liveness.rs

+770-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.