@@ -114,6 +114,8 @@ use rustc_middle::mir::{
114
114
} ;
115
115
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
116
116
117
+ const MAX_LOCALS : usize = 500 ;
118
+
117
119
pub struct DestinationPropagation ;
118
120
119
121
impl < ' tcx > MirPass < ' tcx > for DestinationPropagation {
@@ -137,7 +139,29 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
137
139
relevant_locals. insert ( * src) ;
138
140
}
139
141
142
+ // This pass unfortunately has `O(l² * s)` performance, where `l` is the number of locals
143
+ // and `s` is the number of statements and terminators in the function.
144
+ // To prevent blowing up compile times too much, we bail out when there are too many locals.
145
+ let relevant = relevant_locals. count ( ) ;
146
+ debug ! (
147
+ "{:?}: {} locals ({} relevant), {} blocks" ,
148
+ source. def_id( ) ,
149
+ body. local_decls. len( ) ,
150
+ relevant,
151
+ body. basic_blocks( ) . len( )
152
+ ) ;
153
+ if relevant > MAX_LOCALS {
154
+ warn ! (
155
+ "too many candidate locals in {:?} ({}, max is {}), not optimizing" ,
156
+ source. def_id( ) ,
157
+ relevant,
158
+ MAX_LOCALS
159
+ ) ;
160
+ return ;
161
+ }
162
+
140
163
let mut conflicts = Conflicts :: build ( tcx, body, source, & relevant_locals) ;
164
+
141
165
let mut replacements = Replacements :: new ( body. local_decls . len ( ) ) ;
142
166
for candidate @ CandidateAssignment { dest, src, loc } in candidates {
143
167
// Merge locals that don't conflict.
@@ -392,12 +416,6 @@ impl Conflicts {
392
416
// We don't have to look out for locals that have their address taken, since
393
417
// `find_candidates` already takes care of that.
394
418
395
- debug ! (
396
- "Conflicts::build: {}/{} locals relevant" ,
397
- relevant_locals. count( ) ,
398
- body. local_decls. len( )
399
- ) ;
400
-
401
419
let mut conflicts = BitMatrix :: from_row_n (
402
420
& BitSet :: new_empty ( body. local_decls . len ( ) ) ,
403
421
body. local_decls . len ( ) ,
0 commit comments