Skip to content

Commit a272684

Browse files
committed
Auto merge of #50278 - eddyb:mir-succ-iter, r=nikomatsakis
rustc: return iterators from Terminator(Kind)::successors(_mut). Minor cleanup (and potentially speedup) prompted by @nnethercote's `SmallVec` experiments. This PR assumes `.count()` and `.nth(i)` on `iter::Chain<option::IntoIter, slice::Iter(Mut)>` are `O(1)`, but otherwise all of the uses appear to immediately iterate through the successors. r? @nikomatsakis
2 parents 5a662bf + f0f26b8 commit a272684

File tree

12 files changed

+85
-89
lines changed

12 files changed

+85
-89
lines changed

src/librustc/mir/cache.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ fn calculate_predecessors(mir: &Mir) -> IndexVec<BasicBlock, Vec<BasicBlock>> {
6868
let mut result = IndexVec::from_elem(vec![], mir.basic_blocks());
6969
for (bb, data) in mir.basic_blocks().iter_enumerated() {
7070
if let Some(ref term) = data.terminator {
71-
for &tgt in term.successors().iter() {
71+
for &tgt in term.successors() {
7272
result[tgt].push(bb);
7373
}
7474
}

src/librustc/mir/mod.rs

+66-62
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use hir::{self, InlineAsm};
3636
use std::borrow::{Cow};
3737
use rustc_data_structures::sync::ReadGuard;
3838
use std::fmt::{self, Debug, Formatter, Write};
39-
use std::{iter, mem, u32};
39+
use std::{iter, mem, option, u32};
4040
use std::ops::{Index, IndexMut};
4141
use std::vec::IntoIter;
4242
use syntax::ast::{self, Name};
@@ -862,12 +862,17 @@ pub enum TerminatorKind<'tcx> {
862862
},
863863
}
864864

865+
pub type Successors<'a> =
866+
iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>;
867+
pub type SuccessorsMut<'a> =
868+
iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>;
869+
865870
impl<'tcx> Terminator<'tcx> {
866-
pub fn successors(&self) -> Cow<[BasicBlock]> {
871+
pub fn successors(&self) -> Successors {
867872
self.kind.successors()
868873
}
869874

870-
pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> {
875+
pub fn successors_mut(&mut self) -> SuccessorsMut {
871876
self.kind.successors_mut()
872877
}
873878

@@ -888,72 +893,71 @@ impl<'tcx> TerminatorKind<'tcx> {
888893
}
889894
}
890895

891-
pub fn successors(&self) -> Cow<[BasicBlock]> {
896+
pub fn successors(&self) -> Successors {
892897
use self::TerminatorKind::*;
893898
match *self {
894-
Goto { target: ref b } => slice::from_ref(b).into_cow(),
895-
SwitchInt { targets: ref b, .. } => b[..].into_cow(),
896-
Resume | Abort | GeneratorDrop => (&[]).into_cow(),
897-
Return => (&[]).into_cow(),
898-
Unreachable => (&[]).into_cow(),
899-
Call { destination: Some((_, t)), cleanup: Some(c), .. } => vec![t, c].into_cow(),
900-
Call { destination: Some((_, ref t)), cleanup: None, .. } =>
901-
slice::from_ref(t).into_cow(),
902-
Call { destination: None, cleanup: Some(ref c), .. } => slice::from_ref(c).into_cow(),
903-
Call { destination: None, cleanup: None, .. } => (&[]).into_cow(),
904-
Yield { resume: t, drop: Some(c), .. } => vec![t, c].into_cow(),
905-
Yield { resume: ref t, drop: None, .. } => slice::from_ref(t).into_cow(),
906-
DropAndReplace { target, unwind: Some(unwind), .. } |
907-
Drop { target, unwind: Some(unwind), .. } => {
908-
vec![target, unwind].into_cow()
899+
Resume | Abort | GeneratorDrop | Return | Unreachable |
900+
Call { destination: None, cleanup: None, .. } => {
901+
None.into_iter().chain(&[])
902+
}
903+
Goto { target: ref t } |
904+
Call { destination: None, cleanup: Some(ref t), .. } |
905+
Call { destination: Some((_, ref t)), cleanup: None, .. } |
906+
Yield { resume: ref t, drop: None, .. } |
907+
DropAndReplace { target: ref t, unwind: None, .. } |
908+
Drop { target: ref t, unwind: None, .. } |
909+
Assert { target: ref t, cleanup: None, .. } |
910+
FalseUnwind { real_target: ref t, unwind: None } => {
911+
Some(t).into_iter().chain(&[])
909912
}
910-
DropAndReplace { ref target, unwind: None, .. } |
911-
Drop { ref target, unwind: None, .. } => {
912-
slice::from_ref(target).into_cow()
913+
Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. } |
914+
Yield { resume: ref t, drop: Some(ref u), .. } |
915+
DropAndReplace { target: ref t, unwind: Some(ref u), .. } |
916+
Drop { target: ref t, unwind: Some(ref u), .. } |
917+
Assert { target: ref t, cleanup: Some(ref u), .. } |
918+
FalseUnwind { real_target: ref t, unwind: Some(ref u) } => {
919+
Some(t).into_iter().chain(slice::from_ref(u))
920+
}
921+
SwitchInt { ref targets, .. } => {
922+
None.into_iter().chain(&targets[..])
913923
}
914-
Assert { target, cleanup: Some(unwind), .. } => vec![target, unwind].into_cow(),
915-
Assert { ref target, .. } => slice::from_ref(target).into_cow(),
916924
FalseEdges { ref real_target, ref imaginary_targets } => {
917-
let mut s = vec![*real_target];
918-
s.extend_from_slice(imaginary_targets);
919-
s.into_cow()
925+
Some(real_target).into_iter().chain(&imaginary_targets[..])
920926
}
921-
FalseUnwind { real_target: t, unwind: Some(u) } => vec![t, u].into_cow(),
922-
FalseUnwind { real_target: ref t, unwind: None } => slice::from_ref(t).into_cow(),
923927
}
924928
}
925929

926-
// FIXME: no mootable cow. I’m honestly not sure what a “cow” between `&mut [BasicBlock]` and
927-
// `Vec<&mut BasicBlock>` would look like in the first place.
928-
pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> {
930+
pub fn successors_mut(&mut self) -> SuccessorsMut {
929931
use self::TerminatorKind::*;
930932
match *self {
931-
Goto { target: ref mut b } => vec![b],
932-
SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(),
933-
Resume | Abort | GeneratorDrop => Vec::new(),
934-
Return => Vec::new(),
935-
Unreachable => Vec::new(),
936-
Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut c), .. } => vec![t, c],
937-
Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t],
938-
Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c],
939-
Call { destination: None, cleanup: None, .. } => vec![],
940-
Yield { resume: ref mut t, drop: Some(ref mut c), .. } => vec![t, c],
941-
Yield { resume: ref mut t, drop: None, .. } => vec![t],
942-
DropAndReplace { ref mut target, unwind: Some(ref mut unwind), .. } |
943-
Drop { ref mut target, unwind: Some(ref mut unwind), .. } => vec![target, unwind],
944-
DropAndReplace { ref mut target, unwind: None, .. } |
945-
Drop { ref mut target, unwind: None, .. } => {
946-
vec![target]
933+
Resume | Abort | GeneratorDrop | Return | Unreachable |
934+
Call { destination: None, cleanup: None, .. } => {
935+
None.into_iter().chain(&mut [])
936+
}
937+
Goto { target: ref mut t } |
938+
Call { destination: None, cleanup: Some(ref mut t), .. } |
939+
Call { destination: Some((_, ref mut t)), cleanup: None, .. } |
940+
Yield { resume: ref mut t, drop: None, .. } |
941+
DropAndReplace { target: ref mut t, unwind: None, .. } |
942+
Drop { target: ref mut t, unwind: None, .. } |
943+
Assert { target: ref mut t, cleanup: None, .. } |
944+
FalseUnwind { real_target: ref mut t, unwind: None } => {
945+
Some(t).into_iter().chain(&mut [])
946+
}
947+
Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. } |
948+
Yield { resume: ref mut t, drop: Some(ref mut u), .. } |
949+
DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. } |
950+
Drop { target: ref mut t, unwind: Some(ref mut u), .. } |
951+
Assert { target: ref mut t, cleanup: Some(ref mut u), .. } |
952+
FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
953+
Some(t).into_iter().chain(slice::from_ref_mut(u))
954+
}
955+
SwitchInt { ref mut targets, .. } => {
956+
None.into_iter().chain(&mut targets[..])
947957
}
948-
Assert { ref mut target, cleanup: Some(ref mut unwind), .. } => vec![target, unwind],
949-
Assert { ref mut target, .. } => vec![target],
950958
FalseEdges { ref mut real_target, ref mut imaginary_targets } => {
951-
let mut s = vec![real_target];
952-
s.extend(imaginary_targets.iter_mut());
953-
s
959+
Some(real_target).into_iter().chain(&mut imaginary_targets[..])
954960
}
955-
FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => vec![t, u],
956-
FalseUnwind { ref mut real_target, unwind: None } => vec![real_target],
957961
}
958962
}
959963

@@ -1073,18 +1077,18 @@ impl<'tcx> BasicBlockData<'tcx> {
10731077
impl<'tcx> Debug for TerminatorKind<'tcx> {
10741078
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
10751079
self.fmt_head(fmt)?;
1076-
let successors = self.successors();
1080+
let successor_count = self.successors().count();
10771081
let labels = self.fmt_successor_labels();
1078-
assert_eq!(successors.len(), labels.len());
1082+
assert_eq!(successor_count, labels.len());
10791083

1080-
match successors.len() {
1084+
match successor_count {
10811085
0 => Ok(()),
10821086

1083-
1 => write!(fmt, " -> {:?}", successors[0]),
1087+
1 => write!(fmt, " -> {:?}", self.successors().nth(0).unwrap()),
10841088

10851089
_ => {
10861090
write!(fmt, " -> [")?;
1087-
for (i, target) in successors.iter().enumerate() {
1091+
for (i, target) in self.successors().enumerate() {
10881092
if i > 0 {
10891093
write!(fmt, ", ")?;
10901094
}
@@ -1943,7 +1947,7 @@ impl<'tcx> ControlFlowGraph for Mir<'tcx> {
19431947
fn successors<'graph>(&'graph self, node: Self::Node)
19441948
-> <Self as GraphSuccessors<'graph>>::Iter
19451949
{
1946-
self.basic_blocks[node].terminator().successors().into_owned().into_iter()
1950+
self.basic_blocks[node].terminator().successors().cloned()
19471951
}
19481952
}
19491953

@@ -1954,7 +1958,7 @@ impl<'a, 'b> GraphPredecessors<'b> for Mir<'a> {
19541958

19551959
impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> {
19561960
type Item = BasicBlock;
1957-
type Iter = IntoIter<BasicBlock>;
1961+
type Iter = iter::Cloned<Successors<'b>>;
19581962
}
19591963

19601964
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]

src/librustc/mir/traversal.rs

+5-11
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::vec;
12-
1311
use rustc_data_structures::bitvec::BitVector;
1412
use rustc_data_structures::indexed_vec::Idx;
1513

@@ -67,7 +65,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
6765
let data = &self.mir[idx];
6866

6967
if let Some(ref term) = data.terminator {
70-
for &succ in term.successors().iter() {
68+
for &succ in term.successors() {
7169
self.worklist.push(succ);
7270
}
7371
}
@@ -110,7 +108,7 @@ impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {}
110108
pub struct Postorder<'a, 'tcx: 'a> {
111109
mir: &'a Mir<'tcx>,
112110
visited: BitVector,
113-
visit_stack: Vec<(BasicBlock, vec::IntoIter<BasicBlock>)>
111+
visit_stack: Vec<(BasicBlock, Successors<'a>)>
114112
}
115113

116114
impl<'a, 'tcx> Postorder<'a, 'tcx> {
@@ -126,10 +124,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
126124

127125
if let Some(ref term) = data.terminator {
128126
po.visited.insert(root.index());
129-
130-
let succs = term.successors().into_owned().into_iter();
131-
132-
po.visit_stack.push((root, succs));
127+
po.visit_stack.push((root, term.successors()));
133128
po.traverse_successor();
134129
}
135130

@@ -186,7 +181,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
186181
// two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A]
187182
loop {
188183
let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() {
189-
if let Some(bb) = iter.next() {
184+
if let Some(&bb) = iter.next() {
190185
bb
191186
} else {
192187
break;
@@ -197,8 +192,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
197192

198193
if self.visited.insert(bb.index()) {
199194
if let Some(ref term) = self.mir[bb].terminator {
200-
let succs = term.successors().into_owned().into_iter();
201-
self.visit_stack.push((bb, succs));
195+
self.visit_stack.push((bb, term.successors()));
202196
}
203197
}
204198
}

src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ impl<'gcx, 'tcx> UseFinder<'gcx, 'tcx> {
193193
block_data
194194
.terminator()
195195
.successors()
196-
.iter()
197196
.map(|&basic_block| Location {
198197
statement_index: 0,
199198
block: basic_block,

src/librustc_mir/borrow_check/nll/region_infer/dfs.rs

-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
9595
block_data
9696
.terminator()
9797
.successors()
98-
.iter()
9998
.map(|&basic_block| Location {
10099
statement_index: 0,
101100
block: basic_block,

src/librustc_mir/dataflow/graphviz.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ pub type Node = BasicBlock;
7373
pub struct Edge { source: BasicBlock, index: usize }
7474

7575
fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
76-
let succ_len = mir[bb].terminator().successors().len();
77-
(0..succ_len).map(|index| Edge { source: bb, index: index}).collect()
76+
mir[bb].terminator().successors().enumerate()
77+
.map(|(index, _)| Edge { source: bb, index: index}).collect()
7878
}
7979

8080
impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
@@ -285,6 +285,6 @@ impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
285285

286286
fn target(&self, edge: &Edge) -> Node {
287287
let mir = self.mbcx.mir();
288-
mir[edge.source].terminator().successors()[edge.index]
288+
*mir[edge.source].terminator().successors().nth(edge.index).unwrap()
289289
}
290290
}

src/librustc_mir/transform/inline.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
330330
}
331331

332332
if !is_drop {
333-
for &succ in &term.successors()[..] {
333+
for &succ in term.successors() {
334334
work_list.push(succ);
335335
}
336336
}

src/librustc_mir/transform/remove_noop_landing_pads.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl RemoveNoopLandingPads {
7878
TerminatorKind::SwitchInt { .. } |
7979
TerminatorKind::FalseEdges { .. } |
8080
TerminatorKind::FalseUnwind { .. } => {
81-
terminator.successors().iter().all(|succ| {
81+
terminator.successors().all(|succ| {
8282
nop_landing_pads.contains(succ.index())
8383
})
8484
},

src/librustc_mir/transform/simplify.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
9191

9292
for (_, data) in traversal::preorder(mir) {
9393
if let Some(ref term) = data.terminator {
94-
for &tgt in term.successors().iter() {
94+
for &tgt in term.successors() {
9595
pred_count[tgt] += 1;
9696
}
9797
}
@@ -219,10 +219,10 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
219219
};
220220

221221
let first_succ = {
222-
let successors = terminator.successors();
223-
if let Some(&first_succ) = terminator.successors().get(0) {
224-
if successors.iter().all(|s| *s == first_succ) {
225-
self.pred_count[first_succ] -= (successors.len()-1) as u32;
222+
if let Some(&first_succ) = terminator.successors().nth(0) {
223+
if terminator.successors().all(|s| *s == first_succ) {
224+
let count = terminator.successors().count();
225+
self.pred_count[first_succ] -= (count - 1) as u32;
226226
first_succ
227227
} else {
228228
return false

src/librustc_mir/util/graphviz.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result
125125
let terminator = mir[source].terminator();
126126
let labels = terminator.kind.fmt_successor_labels();
127127

128-
for (&target, label) in terminator.successors().iter().zip(labels) {
128+
for (&target, label) in terminator.successors().zip(labels) {
129129
writeln!(w, r#" {} -> {} [label="{}"];"#, node(source), node(target), label)?;
130130
}
131131

src/librustc_mir/util/liveness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>, mode: LivenessMode) -> Liveness
138138
for b in mir.basic_blocks().indices().rev() {
139139
// outs[b] = ∪ {ins of successors}
140140
bits.clear();
141-
for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() {
141+
for &successor in mir.basic_blocks()[b].terminator().successors() {
142142
bits.union(&ins[successor]);
143143
}
144144
outs[b].clone_from(&bits);

src/librustc_trans/mir/analyze.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock
322322
debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",
323323
bb, data, result[bb], funclet);
324324

325-
for &succ in data.terminator().successors().iter() {
325+
for &succ in data.terminator().successors() {
326326
let kind = result[succ];
327327
debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}",
328328
funclet, succ, kind);

0 commit comments

Comments
 (0)