@@ -44,98 +44,85 @@ impl MirPass for Deaggregator {
4444 return ;
4545 }
4646
47- for bb in mir. basic_blocks_mut ( ) {
48- let mut curr: usize = 0 ;
49- while let Some ( idx) = get_aggregate_statement_index ( curr, & bb. statements ) {
50- // do the replacement
51- debug ! ( "removing statement {:?}" , idx) ;
52- let src_info = bb. statements [ idx] . source_info ;
53- let suffix_stmts = bb. statements . split_off ( idx+1 ) ;
47+ let can_deaggregate = |statement : & Statement | {
48+ if let StatementKind :: Assign ( _, ref rhs) = statement. kind {
49+ if let Rvalue :: Aggregate ( ..) = * rhs {
50+ return true ;
51+ }
52+ }
53+
54+ false
55+ } ;
56+
57+ let ( basic_blocks, local_decls) = mir. basic_blocks_and_local_decls_mut ( ) ;
58+ for bb in basic_blocks {
59+ let mut start = 0 ;
60+ while let Some ( i) = bb. statements [ start..] . iter ( ) . position ( & can_deaggregate) {
61+ let i = start + i;
62+
63+ // FIXME(eddyb) this is probably more expensive than it should be.
64+ // Ideally we'd move the block's statements all at once.
65+ let suffix_stmts = bb. statements . split_off ( i + 1 ) ;
5466 let orig_stmt = bb. statements . pop ( ) . unwrap ( ) ;
55- let ( lhs, rhs) = match orig_stmt. kind {
56- StatementKind :: Assign ( ref lhs, ref rhs) => ( lhs, rhs) ,
57- _ => span_bug ! ( src_info. span, "expected assign, not {:?}" , orig_stmt) ,
58- } ;
59- let ( agg_kind, operands) = match rhs {
60- & Rvalue :: Aggregate ( ref agg_kind, ref operands) => ( agg_kind, operands) ,
61- _ => span_bug ! ( src_info. span, "expected aggregate, not {:?}" , rhs) ,
67+ let source_info = orig_stmt. source_info ;
68+ let ( mut lhs, kind, operands) = match orig_stmt. kind {
69+ StatementKind :: Assign ( lhs, Rvalue :: Aggregate ( kind, operands) )
70+ => ( lhs, kind, operands) ,
71+ _ => bug ! ( )
6272 } ;
63- let ( adt_def, variant, substs) = match * * agg_kind {
64- AggregateKind :: Adt ( adt_def, variant, substs, None )
65- => ( adt_def, variant, substs) ,
66- _ => span_bug ! ( src_info. span, "expected struct, not {:?}" , rhs) ,
73+
74+ let mut set_discriminant = None ;
75+ let active_field_index = match * kind {
76+ AggregateKind :: Adt ( adt_def, variant_index, _, active_field_index) => {
77+ if adt_def. is_enum ( ) {
78+ set_discriminant = Some ( Statement {
79+ kind : StatementKind :: SetDiscriminant {
80+ place : lhs. clone ( ) ,
81+ variant_index,
82+ } ,
83+ source_info,
84+ } ) ;
85+ lhs = lhs. downcast ( adt_def, variant_index) ;
86+ }
87+ active_field_index
88+ }
89+ _ => None
6790 } ;
68- let n = bb. statements . len ( ) ;
69- bb. statements . reserve ( n + operands. len ( ) + suffix_stmts. len ( ) ) ;
70- for ( i, op) in operands. iter ( ) . enumerate ( ) {
71- let ref variant_def = adt_def. variants [ variant] ;
72- let ty = variant_def. fields [ i] . ty ( tcx, substs) ;
73- let rhs = Rvalue :: Use ( op. clone ( ) ) ;
7491
75- let lhs_cast = if adt_def. is_enum ( ) {
76- Place :: Projection ( Box :: new ( PlaceProjection {
77- base : lhs. clone ( ) ,
78- elem : ProjectionElem :: Downcast ( adt_def, variant) ,
79- } ) )
80- } else {
81- lhs. clone ( )
82- } ;
92+ let new_total_count = bb. statements . len ( ) +
93+ operands. len ( ) +
94+ ( set_discriminant. is_some ( ) as usize ) +
95+ suffix_stmts. len ( ) ;
96+ bb. statements . reserve ( new_total_count) ;
8397
84- let lhs_proj = Place :: Projection ( Box :: new ( PlaceProjection {
85- base : lhs_cast,
86- elem : ProjectionElem :: Field ( Field :: new ( i) , ty) ,
87- } ) ) ;
88- let new_statement = Statement {
89- source_info : src_info,
90- kind : StatementKind :: Assign ( lhs_proj, rhs) ,
98+ for ( j, op) in operands. into_iter ( ) . enumerate ( ) {
99+ let lhs_field = if let AggregateKind :: Array ( _) = * kind {
100+ // FIXME(eddyb) `offset` should be u64.
101+ let offset = j as u32 ;
102+ assert_eq ! ( offset as usize , j) ;
103+ lhs. clone ( ) . elem ( ProjectionElem :: ConstantIndex {
104+ offset,
105+ // FIXME(eddyb) `min_length` doesn't appear to be used.
106+ min_length : offset + 1 ,
107+ from_end : false
108+ } )
109+ } else {
110+ let ty = op. ty ( local_decls, tcx) ;
111+ let field = Field :: new ( active_field_index. unwrap_or ( j) ) ;
112+ lhs. clone ( ) . field ( field, ty)
91113 } ;
92- debug ! ( "inserting: {:?} @ {:?}" , new_statement, idx + i) ;
93- bb. statements . push ( new_statement) ;
114+ bb. statements . push ( Statement {
115+ source_info,
116+ kind : StatementKind :: Assign ( lhs_field, Rvalue :: Use ( op) ) ,
117+ } ) ;
94118 }
95119
96- // if the aggregate was an enum, we need to set the discriminant
97- if adt_def. is_enum ( ) {
98- let set_discriminant = Statement {
99- kind : StatementKind :: SetDiscriminant {
100- place : lhs. clone ( ) ,
101- variant_index : variant,
102- } ,
103- source_info : src_info,
104- } ;
105- bb. statements . push ( set_discriminant) ;
106- } ;
120+ // If the aggregate was an enum, we need to set the discriminant.
121+ bb. statements . extend ( set_discriminant) ;
107122
108- curr = bb. statements . len ( ) ;
123+ start = bb. statements . len ( ) ;
109124 bb. statements . extend ( suffix_stmts) ;
110125 }
111126 }
112127 }
113128}
114-
115- fn get_aggregate_statement_index < ' a , ' tcx , ' b > ( start : usize ,
116- statements : & Vec < Statement < ' tcx > > )
117- -> Option < usize > {
118- for i in start..statements. len ( ) {
119- let ref statement = statements[ i] ;
120- let rhs = match statement. kind {
121- StatementKind :: Assign ( _, ref rhs) => rhs,
122- _ => continue ,
123- } ;
124- let ( kind, operands) = match rhs {
125- & Rvalue :: Aggregate ( ref kind, ref operands) => ( kind, operands) ,
126- _ => continue ,
127- } ;
128- let ( adt_def, variant) = match * * kind {
129- AggregateKind :: Adt ( adt_def, variant, _, None ) => ( adt_def, variant) ,
130- _ => continue ,
131- } ;
132- if operands. len ( ) == 0 {
133- // don't deaggregate ()
134- continue ;
135- }
136- debug ! ( "getting variant {:?}" , variant) ;
137- debug ! ( "for adt_def {:?}" , adt_def) ;
138- return Some ( i) ;
139- } ;
140- None
141- }
0 commit comments