@@ -21,116 +21,107 @@ impl MirPass for Deaggregator {
21
21
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
22
22
source : MirSource ,
23
23
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
-
31
24
// Don't run on constant MIR, because trans might not be able to
32
25
// evaluate the modified MIR.
33
26
// FIXME(eddyb) Remove check after miri is merged.
34
27
let id = tcx. hir . as_local_node_id ( source. def_id ) . unwrap ( ) ;
35
28
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
+ }
38
40
}
39
- // In fact, we might not want to trigger in other cases.
40
- // Ex: when we could use SROA. See issue #35259
41
41
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 ) ;
49
65
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 ! ( )
57
71
} ;
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
62
89
} ;
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 ( ) ) ;
69
90
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) ;
78
96
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)
86
112
} ;
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
+ } ) ;
89
117
}
90
118
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) ;
102
121
103
- curr = bb. statements . len ( ) ;
122
+ start = bb. statements . len ( ) ;
104
123
bb. statements . extend ( suffix_stmts) ;
105
124
}
106
125
}
107
126
}
108
127
}
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