Skip to content

Commit

Permalink
Rollup merge of rust-lang#55745 - nnethercote:outlives_components-Sma…
Browse files Browse the repository at this point in the history
…llVec, r=matthewjasper

Convert `outlives_components`' return value to a `SmallVec` outparam.

This avoids some allocations, reducing instruction counts by 1% on a
couple of benchmarks.
  • Loading branch information
pietroalbini authored Nov 10, 2018
2 parents 0e912b2 + 5b2314b commit f0a6e3a
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 42 deletions.
3 changes: 2 additions & 1 deletion src/librustc/infer/opaque_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
17 changes: 9 additions & 8 deletions src/librustc/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//!
Expand Down Expand Up @@ -307,31 +307,32 @@ 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<Component<'tcx>>,
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) => {
self.delegate
.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
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/infer/outlives/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
.map(|subty| self.type_bound(subty))
.collect::<Vec<_>>();

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
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
27 changes: 14 additions & 13 deletions src/librustc/ty/outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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<Component<'tcx>> {
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<Component<'tcx>>) {
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
Expand Down Expand Up @@ -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);
}
Expand All @@ -173,15 +172,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}

fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
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<Component<'tcx>>, regions: Vec<ty::Region<'tcx>>) {
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)));
}
26 changes: 12 additions & 14 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<ty::Region<'tcx>> {
/// 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(_) |
Expand All @@ -1887,9 +1887,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
Param(_) |
Bound(..) |
Infer(_) |
Error => {
vec![]
}
Error => {}
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/librustc_mir/transform/cleanup_post_borrowck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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); }
_ => {},
Expand Down
6 changes: 4 additions & 2 deletions src/librustc_traits/implied_outlives_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
},
Expand All @@ -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<Component<'tcx>>,
sup_components: SmallVec<[Component<'tcx>; 4]>,
) -> Vec<OutlivesBound<'tcx>> {
sup_components
.into_iter()
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_typeck/outlives/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -40,7 +41,9 @@ pub fn insert_outlives_predicate<'tcx>(
//
// Or if within `struct Foo<U>` you had `T = Vec<U>`, 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:
Expand Down

0 comments on commit f0a6e3a

Please sign in to comment.