Skip to content

Commit

Permalink
Auto merge of #76928 - lcnr:opaque-types-cache, r=tmandry
Browse files Browse the repository at this point in the history
cache types during normalization

partially fixes #75992

reduces the following test from 14 to 3 seconds locally.

cc `@Mark-Simulacrum` would it make sense to add that test to `perf`?
```rust
#![recursion_limit="2048"]
#![type_length_limit="112457564"]

pub async fn h0(v: &String, x: &u64) { println!("{} {}", v, x) }
pub async fn h1(v: &String, x: &u64) { h0(v, x).await }
pub async fn h2(v: &String, x: &u64) { h1(v, x).await }
pub async fn h3(v: &String, x: &u64) { h2(v, x).await }
pub async fn h4(v: &String, x: &u64) { h3(v, x).await }
pub async fn h5(v: &String, x: &u64) { h4(v, x).await }
pub async fn h6(v: &String, x: &u64) { h5(v, x).await }
pub async fn h7(v: &String, x: &u64) { h6(v, x).await }
pub async fn h8(v: &String, x: &u64) { h7(v, x).await }
pub async fn h9(v: &String, x: &u64) { h8(v, x).await }

pub async fn h10(v: &String, x: &u64) { h9(v, x).await }
pub async fn h11(v: &String, x: &u64) { h10(v, x).await }
pub async fn h12(v: &String, x: &u64) { h11(v, x).await }
pub async fn h13(v: &String, x: &u64) { h12(v, x).await }
pub async fn h14(v: &String, x: &u64) { h13(v, x).await }
pub async fn h15(v: &String, x: &u64) { h14(v, x).await }
pub async fn h16(v: &String, x: &u64) { h15(v, x).await }
pub async fn h17(v: &String, x: &u64) { h16(v, x).await }
pub async fn h18(v: &String, x: &u64) { h17(v, x).await }
pub async fn h19(v: &String, x: &u64) { h18(v, x).await }

macro_rules! async_recursive {
    (29, $inner:expr) => { async { async_recursive!(28, $inner) }.await };
    (28, $inner:expr) => { async { async_recursive!(27, $inner) }.await };
    (27, $inner:expr) => { async { async_recursive!(26, $inner) }.await };
    (26, $inner:expr) => { async { async_recursive!(25, $inner) }.await };
    (25, $inner:expr) => { async { async_recursive!(24, $inner) }.await };
    (24, $inner:expr) => { async { async_recursive!(23, $inner) }.await };
    (23, $inner:expr) => { async { async_recursive!(22, $inner) }.await };
    (22, $inner:expr) => { async { async_recursive!(21, $inner) }.await };
    (21, $inner:expr) => { async { async_recursive!(20, $inner) }.await };
    (20, $inner:expr) => { async { async_recursive!(19, $inner) }.await };

    (19, $inner:expr) => { async { async_recursive!(18, $inner) }.await };
    (18, $inner:expr) => { async { async_recursive!(17, $inner) }.await };
    (17, $inner:expr) => { async { async_recursive!(16, $inner) }.await };
    (16, $inner:expr) => { async { async_recursive!(15, $inner) }.await };
    (15, $inner:expr) => { async { async_recursive!(14, $inner) }.await };
    (14, $inner:expr) => { async { async_recursive!(13, $inner) }.await };
    (13, $inner:expr) => { async { async_recursive!(12, $inner) }.await };
    (12, $inner:expr) => { async { async_recursive!(11, $inner) }.await };
    (11, $inner:expr) => { async { async_recursive!(10, $inner) }.await };
    (10, $inner:expr) => { async { async_recursive!(9, $inner) }.await };

    (9, $inner:expr) => { async { async_recursive!(8, $inner) }.await };
    (8, $inner:expr) => { async { async_recursive!(7, $inner) }.await };
    (7, $inner:expr) => { async { async_recursive!(6, $inner) }.await };
    (6, $inner:expr) => { async { async_recursive!(5, $inner) }.await };
    (5, $inner:expr) => { async { async_recursive!(4, $inner) }.await };
    (4, $inner:expr) => { async { async_recursive!(3, $inner) }.await };
    (3, $inner:expr) => { async { async_recursive!(2, $inner) }.await };
    (2, $inner:expr) => { async { async_recursive!(1, $inner) }.await };
    (1, $inner:expr) => { async { async_recursive!(0, $inner) }.await };
    (0, $inner:expr) => { async { h19(&String::from("owo"), &0).await; $inner }.await };
}

async fn f() {
    async_recursive!(14, println!("hello"));
}

fn main() {
    let _ = f();
}
```
r? `@eddyb` requires a perf run.
  • Loading branch information
bors committed Sep 22, 2020
2 parents 0da5800 + 1146c39 commit 6d3acf5
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 68 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3467,6 +3467,7 @@ dependencies = [
name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
"arrayvec",
"bitflags",
"cfg-if",
"crossbeam-utils 0.7.2",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_data_structures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition = "2018"
doctest = false

[dependencies]
arrayvec = { version = "0.5.1", default-features = false }
ena = "0.14"
indexmap = "1.5.1"
tracing = "0.1"
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_data_structures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,25 +88,27 @@ pub mod sorted_map;
pub mod stable_set;
#[macro_use]
pub mod stable_hasher;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod sharded;
pub mod stack;
pub mod sync;
pub mod thin_vec;
pub mod tiny_list;
pub mod transitive_relation;
pub use ena::undo_log;
pub use ena::unify;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod mini_map;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;

pub use ena::undo_log;
pub use ena::unify;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
Expand Down
61 changes: 61 additions & 0 deletions compiler/rustc_data_structures/src/mini_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::fx::FxHashMap;
use arrayvec::ArrayVec;

use std::hash::Hash;

/// Small-storage-optimized implementation of a map
/// made specifically for caching results.
///
/// Stores elements in a small array up to a certain length
/// and switches to `HashMap` when that length is exceeded.
pub enum MiniMap<K, V> {
Array(ArrayVec<[(K, V); 8]>),
Map(FxHashMap<K, V>),
}

impl<K: Eq + Hash, V> MiniMap<K, V> {
/// Creates an empty `MiniMap`.
pub fn new() -> Self {
MiniMap::Array(ArrayVec::new())
}

/// Inserts or updates value in the map.
pub fn insert(&mut self, key: K, value: V) {
match self {
MiniMap::Array(array) => {
for pair in array.iter_mut() {
if pair.0 == key {
pair.1 = value;
return;
}
}
if let Err(error) = array.try_push((key, value)) {
let mut map: FxHashMap<K, V> = array.drain(..).collect();
let (key, value) = error.element();
map.insert(key, value);
*self = MiniMap::Map(map);
}
}
MiniMap::Map(map) => {
map.insert(key, value);
}
}
}

/// Return value by key if any.
pub fn get(&self, key: &K) -> Option<&V> {
match self {
MiniMap::Array(array) => {
for pair in array {
if pair.0 == *key {
return Some(&pair.1);
}
}
return None;
}
MiniMap::Map(map) => {
return map.get(key);
}
}
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_index/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ edition = "2018"
doctest = false

[dependencies]
arrayvec = "0.5.1"
arrayvec = { version = "0.5.1", default-features = false }
rustc_serialize = { path = "../rustc_serialize" }
rustc_macros = { path = "../rustc_macros" }
61 changes: 1 addition & 60 deletions compiler/rustc_infer/src/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ use super::unify_key::replace_if_possible;
use super::unify_key::{ConstVarValue, ConstVariableValue};
use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use super::{InferCtxt, MiscVariable, TypeTrace};
use arrayvec::ArrayVec;
use rustc_data_structures::fx::FxHashMap;
use std::hash::Hash;

use crate::traits::{Obligation, PredicateObligations};

use rustc_ast as ast;
use rustc_data_structures::mini_map::MiniMap;
use rustc_hir::def_id::DefId;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
Expand All @@ -47,63 +45,6 @@ use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{IntType, UintType};
use rustc_span::{Span, DUMMY_SP};

/// Small-storage-optimized implementation of a map
/// made specifically for caching results.
///
/// Stores elements in a small array up to a certain length
/// and switches to `HashMap` when that length is exceeded.
enum MiniMap<K, V> {
Array(ArrayVec<[(K, V); 8]>),
Map(FxHashMap<K, V>),
}

impl<K: Eq + Hash, V> MiniMap<K, V> {
/// Creates an empty `MiniMap`.
pub fn new() -> Self {
MiniMap::Array(ArrayVec::new())
}

/// Inserts or updates value in the map.
pub fn insert(&mut self, key: K, value: V) {
match self {
MiniMap::Array(array) => {
for pair in array.iter_mut() {
if pair.0 == key {
pair.1 = value;
return;
}
}
if let Err(error) = array.try_push((key, value)) {
let mut map: FxHashMap<K, V> = array.drain(..).collect();
let (key, value) = error.element();
map.insert(key, value);
*self = MiniMap::Map(map);
}
}
MiniMap::Map(map) => {
map.insert(key, value);
}
}
}

/// Return value by key if any.
pub fn get(&self, key: &K) -> Option<&V> {
match self {
MiniMap::Array(array) => {
for pair in array {
if pair.0 == *key {
return Some(&pair.1);
}
}
return None;
}
MiniMap::Map(map) => {
return map.get(key);
}
}
}
}

#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
pub infcx: &'infcx InferCtxt<'infcx, 'tcx>,
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_trait_selection/src/traits/query/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::infer::canonical::OriginalQueryValues;
use crate::infer::{InferCtxt, InferOk};
use crate::traits::error_reporting::InferCtxtExt;
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
use rustc_data_structures::mini_map::MiniMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::traits::Normalized;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
Expand Down Expand Up @@ -57,6 +58,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
param_env: self.param_env,
obligations: vec![],
error: false,
cache: MiniMap::new(),
anon_depth: 0,
};

Expand Down Expand Up @@ -85,6 +87,7 @@ struct QueryNormalizer<'cx, 'tcx> {
cause: &'cx ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
cache: MiniMap<Ty<'tcx>, Ty<'tcx>>,
error: bool,
anon_depth: usize,
}
Expand All @@ -99,8 +102,12 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
return ty;
}

if let Some(ty) = self.cache.get(&ty) {
return ty;
}

let ty = ty.super_fold_with(self);
match *ty.kind() {
let res = (|| match *ty.kind() {
ty::Opaque(def_id, substs) => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
Expand Down Expand Up @@ -197,7 +204,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
}

_ => ty,
}
})();
self.cache.insert(ty, res);
res
}

fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
Expand Down

0 comments on commit 6d3acf5

Please sign in to comment.