about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonas Schievink <jonasschievink@gmail.com>2020-05-26 21:39:24 +0200
committerJonas Schievink <jonasschievink@gmail.com>2020-09-18 21:23:01 +0200
commitddd6930b549d069ac13de66b8676fed4feb95ec4 (patch)
tree05cfa2d1f72b4e537e417a9c1b1c37ff60100f1b
parentab26fb140c9225c690a219c055a54eba57188d4a (diff)
downloadrust-ddd6930b549d069ac13de66b8676fed4feb95ec4.tar.gz
rust-ddd6930b549d069ac13de66b8676fed4feb95ec4.zip
perf: bail out when there's >500 candidate locals
-rw-r--r--compiler/rustc_mir/src/transform/dest_prop.rs30
1 files changed, 24 insertions, 6 deletions
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs
index d22c11f491b..cb4321ace7f 100644
--- a/compiler/rustc_mir/src/transform/dest_prop.rs
+++ b/compiler/rustc_mir/src/transform/dest_prop.rs
@@ -114,6 +114,8 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
+const MAX_LOCALS: usize = 500;
+
 pub struct DestinationPropagation;
 
 impl<'tcx> MirPass<'tcx> for DestinationPropagation {
@@ -137,7 +139,29 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
             relevant_locals.insert(*src);
         }
 
+        // This pass unfortunately has `O(l² * s)` performance, where `l` is the number of locals
+        // and `s` is the number of statements and terminators in the function.
+        // To prevent blowing up compile times too much, we bail out when there are too many locals.
+        let relevant = relevant_locals.count();
+        debug!(
+            "{:?}: {} locals ({} relevant), {} blocks",
+            source.def_id(),
+            body.local_decls.len(),
+            relevant,
+            body.basic_blocks().len()
+        );
+        if relevant > MAX_LOCALS {
+            warn!(
+                "too many candidate locals in {:?} ({}, max is {}), not optimizing",
+                source.def_id(),
+                relevant,
+                MAX_LOCALS
+            );
+            return;
+        }
+
         let mut conflicts = Conflicts::build(tcx, body, source, &relevant_locals);
+
         let mut replacements = Replacements::new(body.local_decls.len());
         for candidate @ CandidateAssignment { dest, src, loc } in candidates {
             // Merge locals that don't conflict.
@@ -392,12 +416,6 @@ impl Conflicts {
         // We don't have to look out for locals that have their address taken, since
         // `find_candidates` already takes care of that.
 
-        debug!(
-            "Conflicts::build: {}/{} locals relevant",
-            relevant_locals.count(),
-            body.local_decls.len()
-        );
-
         let mut conflicts = BitMatrix::from_row_n(
             &BitSet::new_empty(body.local_decls.len()),
             body.local_decls.len(),