@@ -13,7 +13,12 @@ use rustc::mir::*;
1313use rustc:: mir:: transform:: { MirPass , MirSource } ;
1414use rustc_data_structures:: indexed_vec:: { Idx , IndexVec } ;
1515
16- pub struct AddCallGuards ;
16+ #[ derive( PartialEq ) ]
17+ pub enum AddCallGuards {
18+ AllCallEdges ,
19+ CriticalCallEdges ,
20+ }
21+ pub use self :: AddCallGuards :: * ;
1722
1823/**
1924 * Breaks outgoing critical edges for call terminators in the MIR.
@@ -40,48 +45,52 @@ impl MirPass for AddCallGuards {
4045 _tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
4146 _src : MirSource ,
4247 mir : & mut Mir < ' tcx > ) {
43- add_call_guards ( mir) ;
48+ self . add_call_guards ( mir) ;
4449 }
4550}
4651
47- pub fn add_call_guards ( mir : & mut Mir ) {
48- let pred_count: IndexVec < _ , _ > =
49- mir. predecessors ( ) . iter ( ) . map ( |ps| ps. len ( ) ) . collect ( ) ;
52+ impl AddCallGuards {
53+ pub fn add_call_guards ( & self , mir : & mut Mir ) {
54+ let pred_count: IndexVec < _ , _ > =
55+ mir. predecessors ( ) . iter ( ) . map ( |ps| ps. len ( ) ) . collect ( ) ;
5056
51- // We need a place to store the new blocks generated
52- let mut new_blocks = Vec :: new ( ) ;
57+ // We need a place to store the new blocks generated
58+ let mut new_blocks = Vec :: new ( ) ;
5359
54- let cur_len = mir. basic_blocks ( ) . len ( ) ;
60+ let cur_len = mir. basic_blocks ( ) . len ( ) ;
5561
56- for block in mir. basic_blocks_mut ( ) {
57- match block. terminator {
58- Some ( Terminator {
59- kind : TerminatorKind :: Call {
60- destination : Some ( ( _, ref mut destination) ) ,
61- cleanup : Some ( _) ,
62- ..
63- } , source_info
64- } ) if pred_count[ * destination] > 1 => {
65- // It's a critical edge, break it
66- let call_guard = BasicBlockData {
67- statements : vec ! [ ] ,
68- is_cleanup : block. is_cleanup ,
69- terminator : Some ( Terminator {
70- source_info : source_info,
71- kind : TerminatorKind :: Goto { target : * destination }
72- } )
73- } ;
62+ for block in mir. basic_blocks_mut ( ) {
63+ match block. terminator {
64+ Some ( Terminator {
65+ kind : TerminatorKind :: Call {
66+ destination : Some ( ( _, ref mut destination) ) ,
67+ cleanup,
68+ ..
69+ } , source_info
70+ } ) if pred_count[ * destination] > 1 &&
71+ ( cleanup. is_some ( ) || self == & AllCallEdges ) =>
72+ {
73+ // It's a critical edge, break it
74+ let call_guard = BasicBlockData {
75+ statements : vec ! [ ] ,
76+ is_cleanup : block. is_cleanup ,
77+ terminator : Some ( Terminator {
78+ source_info : source_info,
79+ kind : TerminatorKind :: Goto { target : * destination }
80+ } )
81+ } ;
7482
75- // Get the index it will be when inserted into the MIR
76- let idx = cur_len + new_blocks. len ( ) ;
77- new_blocks. push ( call_guard) ;
78- * destination = BasicBlock :: new ( idx) ;
83+ // Get the index it will be when inserted into the MIR
84+ let idx = cur_len + new_blocks. len ( ) ;
85+ new_blocks. push ( call_guard) ;
86+ * destination = BasicBlock :: new ( idx) ;
87+ }
88+ _ => { }
7989 }
80- _ => { }
8190 }
82- }
8391
84- debug ! ( "Broke {} N edges" , new_blocks. len( ) ) ;
92+ debug ! ( "Broke {} N edges" , new_blocks. len( ) ) ;
8593
86- mir. basic_blocks_mut ( ) . extend ( new_blocks) ;
94+ mir. basic_blocks_mut ( ) . extend ( new_blocks) ;
95+ }
8796}
0 commit comments