From 5b2314b3cacf10e79082180c24c79599e63dbaa9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Nov 2018 19:13:11 +1100 Subject: [PATCH] Use `SmallVec` outparams in several functions. This avoids some allocations, reducing instruction counts by 1% on a couple of benchmarks. --- src/librustc/infer/opaque_types/mod.rs | 3 ++- src/librustc/infer/outlives/obligations.rs | 17 ++++++------ src/librustc/infer/outlives/verify.rs | 3 ++- src/librustc/traits/util.rs | 4 ++- src/librustc/ty/outlives.rs | 27 ++++++++++--------- src/librustc/ty/sty.rs | 26 +++++++++--------- .../transform/cleanup_post_borrowck.rs | 7 ++++- .../implied_outlives_bounds.rs | 6 +++-- src/librustc_typeck/outlives/utils.rs | 5 +++- 9 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 49858972416d8..cc73dd63816aa 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -366,7 +366,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut types = vec![concrete_ty]; let bound_region = |r| self.sub_regions(infer::CallReturn(span), least_region, r); while let Some(ty) = types.pop() { - let mut components = self.tcx.outlives_components(ty); + let mut components = smallvec![]; + self.tcx.push_outlives_components(ty, &mut components); while let Some(component) = components.pop() { match component { Component::Region(r) => { diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index 523f03c2cfc47..f2825887f36e2 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -9,7 +9,7 @@ // except according to those terms. //! Code that handles "type-outlives" constraints like `T: 'a`. This -//! is based on the `outlives_components` function defined on the tcx, +//! is based on the `push_outlives_components` function defined on the tcx, //! but it adds a bit of heuristics on top, in particular to deal with //! associated types and projections. //! @@ -307,17 +307,18 @@ where assert!(!ty.has_escaping_bound_vars()); - let components = self.tcx.outlives_components(ty); - self.components_must_outlive(origin, components, region); + let mut components = smallvec![]; + self.tcx.push_outlives_components(ty, &mut components); + self.components_must_outlive(origin, &components, region); } fn components_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, - components: Vec>, + components: &[Component<'tcx>], region: ty::Region<'tcx>, ) { - for component in components { + for component in components.iter() { let origin = origin.clone(); match component { Component::Region(region1) => { @@ -325,13 +326,13 @@ where .push_sub_region_constraint(origin, region, region1); } Component::Param(param_ty) => { - self.param_ty_must_outlive(origin, region, param_ty); + self.param_ty_must_outlive(origin, region, *param_ty); } Component::Projection(projection_ty) => { - self.projection_must_outlive(origin, region, projection_ty); + self.projection_must_outlive(origin, region, *projection_ty); } Component::EscapingProjection(subcomponents) => { - self.components_must_outlive(origin, subcomponents, region); + self.components_must_outlive(origin, &subcomponents, region); } Component::UnresolvedInferenceVariable(v) => { // ignore this, we presume it will yield an error diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs index 88d45671b9afd..a7a79dd2e6560 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc/infer/outlives/verify.rs @@ -155,7 +155,8 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> { .map(|subty| self.type_bound(subty)) .collect::>(); - let mut regions = ty.regions(); + let mut regions = smallvec![]; + ty.push_regions(&mut regions); regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions bounds.push(VerifyBound::AllBounds( regions diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 74f8d67ce0484..9a2f484125de7 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -200,8 +200,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { } let visited = &mut self.visited; + let mut components = smallvec![]; + tcx.push_outlives_components(ty_max, &mut components); self.stack.extend( - tcx.outlives_components(ty_max) + components .into_iter() .filter_map(|component| match component { Component::Region(r) => if r.is_late_bound() { diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 449730c9d0601..7fac88a3d78f1 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -12,6 +12,7 @@ // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that // RFC for reference. +use smallvec::SmallVec; use ty::{self, Ty, TyCtxt, TypeFoldable}; #[derive(Debug)] @@ -55,17 +56,15 @@ pub enum Component<'tcx> { } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - /// Returns all the things that must outlive `'a` for the condition + /// Push onto `out` all the things that must outlive `'a` for the condition /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. - pub fn outlives_components(&self, ty0: Ty<'tcx>) - -> Vec> { - let mut components = vec![]; - self.compute_components(ty0, &mut components); - debug!("components({:?}) = {:?}", ty0, components); - components + pub fn push_outlives_components(&self, ty0: Ty<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>) { + self.compute_components(ty0, out); + debug!("components({:?}) = {:?}", ty0, out); } - fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec>) { + fn compute_components(&self, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { // Descend through the types, looking for the various "base" // components and collecting them into `out`. This is not written // with `collect()` because of the need to sometimes skip subtrees @@ -164,7 +163,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // list is maintained explicitly, because bound regions // themselves can be readily identified. - push_region_constraints(out, ty.regions()); + push_region_constraints(ty, out); for subty in ty.walk_shallow() { self.compute_components(subty, out); } @@ -173,15 +172,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } fn capture_components(&self, ty: Ty<'tcx>) -> Vec> { - let mut temp = vec![]; - push_region_constraints(&mut temp, ty.regions()); + let mut temp = smallvec![]; + push_region_constraints(ty, &mut temp); for subty in ty.walk_shallow() { self.compute_components(subty, &mut temp); } - temp + temp.into_iter().collect() } } -fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec>) { +fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { + let mut regions = smallvec![]; + ty.push_regions(&mut regions); out.extend(regions.iter().filter(|&r| !r.is_late_bound()).map(|r| Component::Region(r))); } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 28b58d62175bc..5084f859c0782 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -22,6 +22,7 @@ use ty::{List, TyS, ParamEnvAnd, ParamEnv}; use util::captures::Captures; use mir::interpret::{Scalar, Pointer}; +use smallvec::SmallVec; use std::iter; use std::cmp::Ordering; use rustc_target::spec::abi; @@ -1846,28 +1847,27 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - /// Returns the regions directly referenced from this type (but - /// not types reachable from this type via `walk_tys`). This - /// ignores late-bound regions binders. - pub fn regions(&self) -> Vec> { + /// Push onto `out` the regions directly referenced from this type (but not + /// types reachable from this type via `walk_tys`). This ignores late-bound + /// regions binders. + pub fn push_regions(&self, out: &mut SmallVec<[ty::Region<'tcx>; 4]>) { match self.sty { Ref(region, _, _) => { - vec![region] + out.push(region); } Dynamic(ref obj, region) => { - let mut v = vec![region]; - v.extend(obj.principal().skip_binder().substs.regions()); - v + out.push(region); + out.extend(obj.principal().skip_binder().substs.regions()); } Adt(_, substs) | Opaque(_, substs) => { - substs.regions().collect() + out.extend(substs.regions()) } Closure(_, ClosureSubsts { ref substs }) | Generator(_, GeneratorSubsts { ref substs }, _) => { - substs.regions().collect() + out.extend(substs.regions()) } Projection(ref data) | UnnormalizedProjection(ref data) => { - data.substs.regions().collect() + out.extend(data.substs.regions()) } FnDef(..) | FnPtr(_) | @@ -1887,9 +1887,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { Param(_) | Bound(..) | Infer(_) | - Error => { - vec![] - } + Error => {} } } diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 4d3b422ab2817..98311444e2871 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -37,6 +37,7 @@ use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place}; use rustc::mir::{Rvalue, Statement, StatementKind}; use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; use rustc::ty::{Ty, RegionKind, TyCtxt}; +use smallvec::smallvec; use transform::{MirPass, MirSource}; pub struct CleanEndRegions; @@ -80,7 +81,11 @@ impl<'tcx> Visitor<'tcx> for GatherBorrowedRegions { fn visit_ty(&mut self, ty: &Ty<'tcx>, _: TyContext) { // Gather regions that occur in types - for re in ty.walk().flat_map(|t| t.regions()) { + let mut regions = smallvec![]; + for t in ty.walk() { + t.push_regions(&mut regions); + } + for re in regions { match *re { RegionKind::ReScope(ce) => { self.seen_regions.insert(ce); } _ => {}, diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 7cc064f9c3d3d..7514c2c18e7ca 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -20,6 +20,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::outlives::Component; use rustc::ty::query::Providers; use rustc::ty::wf; +use smallvec::{SmallVec, smallvec}; use syntax::ast::DUMMY_NODE_ID; use syntax::source_map::DUMMY_SP; use rustc::traits::FulfillmentContext; @@ -133,7 +134,8 @@ fn compute_implied_outlives_bounds<'tcx>( None => vec![], Some(ty::OutlivesPredicate(ty_a, r_b)) => { let ty_a = infcx.resolve_type_vars_if_possible(&ty_a); - let components = tcx.outlives_components(ty_a); + let mut components = smallvec![]; + tcx.push_outlives_components(ty_a, &mut components); implied_bounds_from_components(r_b, components) } }, @@ -155,7 +157,7 @@ fn compute_implied_outlives_bounds<'tcx>( /// those relationships. fn implied_bounds_from_components( sub_region: ty::Region<'tcx>, - sup_components: Vec>, + sup_components: SmallVec<[Component<'tcx>; 4]>, ) -> Vec> { sup_components .into_iter() diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index d748d93d8988e..6ed59837eb49a 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -11,6 +11,7 @@ use rustc::ty::outlives::Component; use rustc::ty::subst::{Kind, UnpackedKind}; use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt}; +use smallvec::smallvec; use std::collections::BTreeSet; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred @@ -40,7 +41,9 @@ pub fn insert_outlives_predicate<'tcx>( // // Or if within `struct Foo` you had `T = Vec`, then // we would want to add `U: 'outlived_region` - for component in tcx.outlives_components(ty) { + let mut components = smallvec![]; + tcx.push_outlives_components(ty, &mut components); + for component in components { match component { Component::Region(r) => { // This would arise from something like: