@@ -114,6 +114,8 @@ use rustc_middle::mir::{
114114} ;
115115use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
116116
117+ const MAX_LOCALS : usize = 500 ;
118+
117119pub struct DestinationPropagation ;
118120
119121impl < ' tcx > MirPass < ' tcx > for DestinationPropagation {
@@ -137,7 +139,29 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
137139 relevant_locals. insert ( * src) ;
138140 }
139141
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+
140163 let mut conflicts = Conflicts :: build ( tcx, body, source, & relevant_locals) ;
164+
141165 let mut replacements = Replacements :: new ( body. local_decls . len ( ) ) ;
142166 for candidate @ CandidateAssignment { dest, src, loc } in candidates {
143167 // Merge locals that don't conflict.
@@ -392,12 +416,6 @@ impl Conflicts {
392416 // We don't have to look out for locals that have their address taken, since
393417 // `find_candidates` already takes care of that.
394418
395- debug ! (
396- "Conflicts::build: {}/{} locals relevant" ,
397- relevant_locals. count( ) ,
398- body. local_decls. len( )
399- ) ;
400-
401419 let mut conflicts = BitMatrix :: from_row_n (
402420 & BitSet :: new_empty ( body. local_decls . len ( ) ) ,
403421 body. local_decls . len ( ) ,
0 commit comments