|
| 1 | +use mir::repr::*; |
| 2 | + |
| 3 | +use std::ops::{Index, IndexMut}; |
| 4 | +use syntax::codemap::Span; |
| 5 | + |
| 6 | +#[derive(Clone, RustcEncodable, RustcDecodable)] |
| 7 | +pub struct CFG<'tcx> { |
| 8 | + pub basic_blocks: Vec<BasicBlockData<'tcx>>, |
| 9 | +} |
| 10 | + |
| 11 | +pub struct PredecessorIter(::std::vec::IntoIter<BasicBlock>); |
| 12 | +impl Iterator for PredecessorIter { |
| 13 | + type Item = BasicBlock; |
| 14 | + fn next(&mut self) -> Option<BasicBlock> { |
| 15 | + self.0.next() |
| 16 | + } |
| 17 | +} |
| 18 | + |
| 19 | +pub struct SuccessorIter(::std::vec::IntoIter<BasicBlock>); |
| 20 | +impl<'a> Iterator for SuccessorIter { |
| 21 | + type Item = BasicBlock; |
| 22 | + fn next(&mut self) -> Option<BasicBlock> { |
| 23 | + self.0.next() |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +pub struct SuccessorIterMut<'a>(::std::vec::IntoIter<&'a mut BasicBlock>); |
| 28 | +impl<'a> Iterator for SuccessorIterMut<'a> { |
| 29 | + type Item = &'a mut BasicBlock; |
| 30 | + fn next(&mut self) -> Option<&'a mut BasicBlock> { |
| 31 | + self.0.next() |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +impl<'tcx> CFG<'tcx> { |
| 36 | + pub fn len(&self) -> usize { |
| 37 | + self.basic_blocks.len() |
| 38 | + } |
| 39 | + |
| 40 | + pub fn predecessors(&self, b: BasicBlock) -> PredecessorIter { |
| 41 | + let mut preds = vec![]; |
| 42 | + for idx in 0..self.len() { |
| 43 | + let bb = BasicBlock::new(idx); |
| 44 | + if let Some(_) = self.successors(bb).find(|&x| x == b) { |
| 45 | + preds.push(bb) |
| 46 | + } |
| 47 | + } |
| 48 | + PredecessorIter(preds.into_iter()) |
| 49 | + } |
| 50 | + |
| 51 | + pub fn successors(&self, b: BasicBlock) -> SuccessorIter { |
| 52 | + let v: Vec<BasicBlock> = self[b].terminator().kind.successors().into_owned(); |
| 53 | + SuccessorIter(v.into_iter()) |
| 54 | + } |
| 55 | + |
| 56 | + pub fn successors_mut(&mut self, b: BasicBlock) -> SuccessorIterMut { |
| 57 | + SuccessorIterMut(self[b].terminator_mut().kind.successors_mut().into_iter()) |
| 58 | + } |
| 59 | + |
| 60 | + |
| 61 | + pub fn swap(&mut self, b1: BasicBlock, b2: BasicBlock) { |
| 62 | + // TODO: find all the branches to b2 from subgraph starting at b2 and replace them with b1. |
| 63 | + self.basic_blocks.swap(b1.index(), b2.index()); |
| 64 | + } |
| 65 | + |
| 66 | + pub fn start_new_block(&mut self) -> BasicBlock { |
| 67 | + let node_index = self.basic_blocks.len(); |
| 68 | + self.basic_blocks.push(BasicBlockData::new(None)); |
| 69 | + BasicBlock::new(node_index) |
| 70 | + } |
| 71 | + |
| 72 | + pub fn start_new_cleanup_block(&mut self) -> BasicBlock { |
| 73 | + let bb = self.start_new_block(); |
| 74 | + self[bb].is_cleanup = true; |
| 75 | + bb |
| 76 | + } |
| 77 | + |
| 78 | + pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) { |
| 79 | + debug!("push({:?}, {:?})", block, statement); |
| 80 | + self[block].statements.push(statement); |
| 81 | + } |
| 82 | + |
| 83 | + pub fn terminate(&mut self, |
| 84 | + block: BasicBlock, |
| 85 | + scope: ScopeId, |
| 86 | + span: Span, |
| 87 | + kind: TerminatorKind<'tcx>) { |
| 88 | + debug_assert!(self[block].terminator.is_none(), |
| 89 | + "terminate: block {:?} already has a terminator set", block); |
| 90 | + self[block].terminator = Some(Terminator { |
| 91 | + span: span, |
| 92 | + scope: scope, |
| 93 | + kind: kind, |
| 94 | + }); |
| 95 | + } |
| 96 | + |
| 97 | + pub fn push_assign(&mut self, |
| 98 | + block: BasicBlock, |
| 99 | + scope: ScopeId, |
| 100 | + span: Span, |
| 101 | + lvalue: &Lvalue<'tcx>, |
| 102 | + rvalue: Rvalue<'tcx>) { |
| 103 | + self.push(block, Statement { |
| 104 | + scope: scope, |
| 105 | + span: span, |
| 106 | + kind: StatementKind::Assign(lvalue.clone(), rvalue) |
| 107 | + }); |
| 108 | + } |
| 109 | + |
| 110 | + pub fn push_assign_constant(&mut self, |
| 111 | + block: BasicBlock, |
| 112 | + scope: ScopeId, |
| 113 | + span: Span, |
| 114 | + temp: &Lvalue<'tcx>, |
| 115 | + constant: Constant<'tcx>) { |
| 116 | + self.push_assign(block, scope, span, temp, |
| 117 | + Rvalue::Use(Operand::Constant(constant))); |
| 118 | + } |
| 119 | + |
| 120 | + pub fn push_assign_unit(&mut self, |
| 121 | + block: BasicBlock, |
| 122 | + scope: ScopeId, |
| 123 | + span: Span, |
| 124 | + lvalue: &Lvalue<'tcx>) { |
| 125 | + self.push_assign(block, scope, span, lvalue, Rvalue::Aggregate( |
| 126 | + AggregateKind::Tuple, vec![] |
| 127 | + )); |
| 128 | + } |
| 129 | +} |
| 130 | + |
| 131 | +impl<'tcx> Index<BasicBlock> for CFG<'tcx> { |
| 132 | + type Output = BasicBlockData<'tcx>; |
| 133 | + |
| 134 | + #[inline] |
| 135 | + fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { |
| 136 | + &self.basic_blocks[index.index()] |
| 137 | + } |
| 138 | +} |
| 139 | + |
| 140 | +impl<'tcx> IndexMut<BasicBlock> for CFG<'tcx> { |
| 141 | + #[inline] |
| 142 | + fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { |
| 143 | + &mut self.basic_blocks[index.index()] |
| 144 | + } |
| 145 | +} |
| 146 | + |
0 commit comments