@@ -21,116 +21,107 @@ impl MirPass for Deaggregator {
2121 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
2222 source : MirSource ,
2323 mir : & mut Mir < ' tcx > ) {
24- let node_path = tcx. item_path_str ( source. def_id ) ;
25- debug ! ( "running on: {:?}" , node_path) ;
26- // we only run when mir_opt_level > 2
27- if tcx. sess . opts . debugging_opts . mir_opt_level <= 2 {
28- return ;
29- }
30-
3124 // Don't run on constant MIR, because trans might not be able to
3225 // evaluate the modified MIR.
3326 // FIXME(eddyb) Remove check after miri is merged.
3427 let id = tcx. hir . as_local_node_id ( source. def_id ) . unwrap ( ) ;
3528 match ( tcx. hir . body_owner_kind ( id) , source. promoted ) {
36- ( hir:: BodyOwnerKind :: Fn , None ) => { } ,
37- _ => return
29+ ( _, Some ( _) ) |
30+ ( hir:: BodyOwnerKind :: Const , _) |
31+ ( hir:: BodyOwnerKind :: Static ( _) , _) => return ,
32+
33+ ( hir:: BodyOwnerKind :: Fn , _) => {
34+ if tcx. is_const_fn ( source. def_id ) {
35+ // Don't run on const functions, as, again, trans might not be able to evaluate
36+ // the optimized IR.
37+ return
38+ }
39+ }
3840 }
39- // In fact, we might not want to trigger in other cases.
40- // Ex: when we could use SROA. See issue #35259
4141
42- for bb in mir. basic_blocks_mut ( ) {
43- let mut curr: usize = 0 ;
44- while let Some ( idx) = get_aggregate_statement_index ( curr, & bb. statements ) {
45- // do the replacement
46- debug ! ( "removing statement {:?}" , idx) ;
47- let src_info = bb. statements [ idx] . source_info ;
48- let suffix_stmts = bb. statements . split_off ( idx+1 ) ;
42+ let can_deaggregate = |statement : & Statement | {
43+ if let StatementKind :: Assign ( _, ref rhs) = statement. kind {
44+ if let Rvalue :: Aggregate ( ref kind, _) = * rhs {
45+ // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
46+ if let AggregateKind :: Array ( _) = * * kind {
47+ return false ;
48+ }
49+ return true ;
50+ }
51+ }
52+
53+ false
54+ } ;
55+
56+ let ( basic_blocks, local_decls) = mir. basic_blocks_and_local_decls_mut ( ) ;
57+ for bb in basic_blocks {
58+ let mut start = 0 ;
59+ while let Some ( i) = bb. statements [ start..] . iter ( ) . position ( & can_deaggregate) {
60+ let i = start + i;
61+
62+ // FIXME(eddyb) this is probably more expensive than it should be.
63+ // Ideally we'd move the block's statements all at once.
64+ let suffix_stmts = bb. statements . split_off ( i + 1 ) ;
4965 let orig_stmt = bb. statements . pop ( ) . unwrap ( ) ;
50- let ( lhs, rhs) = match orig_stmt. kind {
51- StatementKind :: Assign ( ref lhs, ref rhs) => ( lhs, rhs) ,
52- _ => span_bug ! ( src_info. span, "expected assign, not {:?}" , orig_stmt) ,
53- } ;
54- let ( agg_kind, operands) = match rhs {
55- & Rvalue :: Aggregate ( ref agg_kind, ref operands) => ( agg_kind, operands) ,
56- _ => span_bug ! ( src_info. span, "expected aggregate, not {:?}" , rhs) ,
66+ let source_info = orig_stmt. source_info ;
67+ let ( mut lhs, kind, operands) = match orig_stmt. kind {
68+ StatementKind :: Assign ( lhs, Rvalue :: Aggregate ( kind, operands) )
69+ => ( lhs, kind, operands) ,
70+ _ => bug ! ( )
5771 } ;
58- let ( adt_def, variant, substs) = match * * agg_kind {
59- AggregateKind :: Adt ( adt_def, variant, substs, None )
60- => ( adt_def, variant, substs) ,
61- _ => span_bug ! ( src_info. span, "expected struct, not {:?}" , rhs) ,
72+
73+ let mut set_discriminant = None ;
74+ let active_field_index = match * kind {
75+ AggregateKind :: Adt ( adt_def, variant_index, _, active_field_index) => {
76+ if adt_def. is_enum ( ) {
77+ set_discriminant = Some ( Statement {
78+ kind : StatementKind :: SetDiscriminant {
79+ place : lhs. clone ( ) ,
80+ variant_index,
81+ } ,
82+ source_info,
83+ } ) ;
84+ lhs = lhs. downcast ( adt_def, variant_index) ;
85+ }
86+ active_field_index
87+ }
88+ _ => None
6289 } ;
63- let n = bb. statements . len ( ) ;
64- bb. statements . reserve ( n + operands. len ( ) + suffix_stmts. len ( ) ) ;
65- for ( i, op) in operands. iter ( ) . enumerate ( ) {
66- let ref variant_def = adt_def. variants [ variant] ;
67- let ty = variant_def. fields [ i] . ty ( tcx, substs) ;
68- let rhs = Rvalue :: Use ( op. clone ( ) ) ;
6990
70- let lhs_cast = if adt_def. is_enum ( ) {
71- Place :: Projection ( Box :: new ( PlaceProjection {
72- base : lhs. clone ( ) ,
73- elem : ProjectionElem :: Downcast ( adt_def, variant) ,
74- } ) )
75- } else {
76- lhs. clone ( )
77- } ;
91+ let new_total_count = bb. statements . len ( ) +
92+ operands. len ( ) +
93+ ( set_discriminant. is_some ( ) as usize ) +
94+ suffix_stmts. len ( ) ;
95+ bb. statements . reserve ( new_total_count) ;
7896
79- let lhs_proj = Place :: Projection ( Box :: new ( PlaceProjection {
80- base : lhs_cast,
81- elem : ProjectionElem :: Field ( Field :: new ( i) , ty) ,
82- } ) ) ;
83- let new_statement = Statement {
84- source_info : src_info,
85- kind : StatementKind :: Assign ( lhs_proj, rhs) ,
97+ for ( j, op) in operands. into_iter ( ) . enumerate ( ) {
98+ let lhs_field = if let AggregateKind :: Array ( _) = * kind {
99+ // FIXME(eddyb) `offset` should be u64.
100+ let offset = j as u32 ;
101+ assert_eq ! ( offset as usize , j) ;
102+ lhs. clone ( ) . elem ( ProjectionElem :: ConstantIndex {
103+ offset,
104+ // FIXME(eddyb) `min_length` doesn't appear to be used.
105+ min_length : offset + 1 ,
106+ from_end : false
107+ } )
108+ } else {
109+ let ty = op. ty ( local_decls, tcx) ;
110+ let field = Field :: new ( active_field_index. unwrap_or ( j) ) ;
111+ lhs. clone ( ) . field ( field, ty)
86112 } ;
87- debug ! ( "inserting: {:?} @ {:?}" , new_statement, idx + i) ;
88- bb. statements . push ( new_statement) ;
113+ bb. statements . push ( Statement {
114+ source_info,
115+ kind : StatementKind :: Assign ( lhs_field, Rvalue :: Use ( op) ) ,
116+ } ) ;
89117 }
90118
91- // if the aggregate was an enum, we need to set the discriminant
92- if adt_def. is_enum ( ) {
93- let set_discriminant = Statement {
94- kind : StatementKind :: SetDiscriminant {
95- place : lhs. clone ( ) ,
96- variant_index : variant,
97- } ,
98- source_info : src_info,
99- } ;
100- bb. statements . push ( set_discriminant) ;
101- } ;
119+ // If the aggregate was an enum, we need to set the discriminant.
120+ bb. statements . extend ( set_discriminant) ;
102121
103- curr = bb. statements . len ( ) ;
122+ start = bb. statements . len ( ) ;
104123 bb. statements . extend ( suffix_stmts) ;
105124 }
106125 }
107126 }
108127}
109-
110- fn get_aggregate_statement_index < ' a , ' tcx , ' b > ( start : usize ,
111- statements : & Vec < Statement < ' tcx > > )
112- -> Option < usize > {
113- for i in start..statements. len ( ) {
114- let ref statement = statements[ i] ;
115- let rhs = match statement. kind {
116- StatementKind :: Assign ( _, ref rhs) => rhs,
117- _ => continue ,
118- } ;
119- let ( kind, operands) = match rhs {
120- & Rvalue :: Aggregate ( ref kind, ref operands) => ( kind, operands) ,
121- _ => continue ,
122- } ;
123- let ( adt_def, variant) = match * * kind {
124- AggregateKind :: Adt ( adt_def, variant, _, None ) => ( adt_def, variant) ,
125- _ => continue ,
126- } ;
127- if operands. len ( ) == 0 {
128- // don't deaggregate ()
129- continue ;
130- }
131- debug ! ( "getting variant {:?}" , variant) ;
132- debug ! ( "for adt_def {:?}" , adt_def) ;
133- return Some ( i) ;
134- } ;
135- None
136- }
0 commit comments