Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use PlaceBuilder to avoid a lot of slice -> vec -> slice convertions #64922

Merged
merged 1 commit into from
Oct 2, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 114 additions & 30 deletions src/librustc_mir/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,79 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::hair::*;
use rustc::mir::interpret::{PanicInfo::BoundsCheck};
use rustc::mir::*;
use rustc::ty::{CanonicalUserTypeAnnotation, Variance};
use rustc::ty::{CanonicalUserTypeAnnotation, Ty, Variance};

use rustc_data_structures::indexed_vec::Idx;

/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
/// place by pushing more and more projections onto the end, and then convert the final set into a
/// place using the `into_place` method.
///
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
#[derive(Clone)]
struct PlaceBuilder<'tcx> {
spastorino marked this conversation as resolved.
Show resolved Hide resolved
base: PlaceBase<'tcx>,
projection: Vec<PlaceElem<'tcx>>,
}

impl PlaceBuilder<'tcx> {
fn into_place(self) -> Place<'tcx> {
Place {
base: self.base,
projection: self.projection.into_boxed_slice(),
}
}

fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
self.project(PlaceElem::Field(f, ty))
}

fn deref(self) -> Self {
self.project(PlaceElem::Deref)
}

fn index(self, index: Local) -> Self {
self.project(PlaceElem::Index(index))
}

fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
self.projection.push(elem);
self
}
}

impl From<Local> for PlaceBuilder<'tcx> {
fn from(local: Local) -> Self {
Self {
base: local.into(),
projection: Vec::new(),
}
}
}

impl From<PlaceBase<'tcx>> for PlaceBuilder<'tcx> {
fn from(base: PlaceBase<'tcx>) -> Self {
Self {
base,
projection: Vec::new(),
}
}
}

impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, yielding a place that we can move from etc.
pub fn as_place<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
pub fn as_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let place_builder = unpack!(block = self.as_place_builder(block, expr));
block.and(place_builder.into_place())
}

/// This is used when constructing a compound `Place`, so that we can avoid creating
/// intermediate `Place` values until we know the full set of projections.
fn as_place_builder<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<PlaceBuilder<'tcx>>
spastorino marked this conversation as resolved.
Show resolved Hide resolved
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
Expand All @@ -25,7 +91,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// place. The place itself may or may not be mutable:
/// * If this expr is a place expr like a.b, then we will return that place.
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
pub fn as_read_only_place<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
pub fn as_read_only_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
block.and(place_builder.into_place())
}

/// This is used when constructing a compound `Place`, so that we can avoid creating
/// intermediate `Place` values until we know the full set of projections.
/// Mutability note: The caller of this method promises only to read from the resulting
/// place. The place itself may or may not be mutable:
/// * If this expr is a place expr like a.b, then we will return that place.
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
fn as_read_only_place_builder<M>(
&mut self,
block: BasicBlock,
expr: M,
) -> BlockAnd<PlaceBuilder<'tcx>>
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
Expand All @@ -38,7 +122,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
mut block: BasicBlock,
expr: Expr<'tcx>,
mutability: Mutability,
) -> BlockAnd<Place<'tcx>> {
) -> BlockAnd<PlaceBuilder<'tcx>> {
debug!(
"expr_as_place(block={:?}, expr={:?}, mutability={:?})",
block, expr, mutability
Expand All @@ -54,25 +138,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
value,
} => this.in_scope((region_scope, source_info), lint_level, |this| {
if mutability == Mutability::Not {
this.as_read_only_place(block, value)
this.as_read_only_place_builder(block, value)
} else {
this.as_place(block, value)
this.as_place_builder(block, value)
}
}),
ExprKind::Field { lhs, name } => {
let place = unpack!(block = this.as_place(block, lhs));
let place = place.field(name, expr.ty);
block.and(place)
let place_builder = unpack!(block = this.as_place_builder(block, lhs));
block.and(place_builder.field(name, expr.ty))
}
ExprKind::Deref { arg } => {
let place = unpack!(block = this.as_place(block, arg));
let place = place.deref();
block.and(place)
let place_builder = unpack!(block = this.as_place_builder(block, arg));
block.and(place_builder.deref())
}
ExprKind::Index { lhs, index } => {
let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());

let slice = unpack!(block = this.as_place(block, lhs));
let place_builder = unpack!(block = this.as_place_builder(block, lhs));
// Making this a *fresh* temporary also means we do not have to worry about
// the index changing later: Nothing will ever change this temporary.
// The "retagging" transformation (for Stacked Borrows) relies on this.
Expand All @@ -83,6 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Mutability::Not,
));

let slice = place_builder.clone().into_place();
// bounds check:
let (len, lt) = (
this.temp(usize_ty.clone(), expr_span),
Expand All @@ -92,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block,
source_info, // len = len(slice)
&len,
Rvalue::Len(slice.clone()),
Rvalue::Len(slice),
);
this.cfg.push_assign(
block,
Expand All @@ -110,30 +193,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
index: Operand::Copy(Place::from(idx)),
};
let success = this.assert(block, Operand::Move(lt), true, msg, expr_span);
success.and(slice.index(idx))
success.and(place_builder.index(idx))
}
ExprKind::SelfRef => block.and(Place::from(Local::new(1))),
ExprKind::SelfRef => block.and(PlaceBuilder::from(Local::new(1))),
ExprKind::VarRef { id } => {
let place = if this.is_bound_var_in_guard(id) {
let place_builder = if this.is_bound_var_in_guard(id) {
let index = this.var_local_id(id, RefWithinGuard);
Place::from(index).deref()
PlaceBuilder::from(index).deref()
} else {
let index = this.var_local_id(id, OutsideGuard);
Place::from(index)
PlaceBuilder::from(index)
};
block.and(place)
block.and(place_builder)
}
ExprKind::StaticRef { id } => block.and(Place {
base: PlaceBase::Static(Box::new(Static {
ExprKind::StaticRef { id } => block.and(PlaceBuilder::from(
PlaceBase::Static(Box::new(Static {
ty: expr.ty,
kind: StaticKind::Static,
def_id: id,
})),
projection: box [],
}),
}))
)),

ExprKind::PlaceTypeAscription { source, user_ty } => {
let place = unpack!(block = this.as_place(block, source));
let place_builder = unpack!(block = this.as_place_builder(block, source));
if let Some(user_ty) = user_ty {
let annotation_index = this.canonical_user_type_annotations.push(
CanonicalUserTypeAnnotation {
Expand All @@ -142,21 +224,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
inferred_ty: expr.ty,
}
);

let place = place_builder.clone().into_place();
this.cfg.push(
block,
Statement {
source_info,
kind: StatementKind::AscribeUserType(
box(
place.clone(),
place,
UserTypeProjection { base: annotation_index, projs: vec![], }
),
Variance::Invariant,
),
},
);
}
block.and(place)
block.and(place_builder)
}
ExprKind::ValueTypeAscription { source, user_ty } => {
let source = this.hir.mirror(source);
Expand Down Expand Up @@ -185,7 +269,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
},
);
}
block.and(Place::from(temp))
block.and(PlaceBuilder::from(temp))
}

ExprKind::Array { .. }
Expand Down Expand Up @@ -221,7 +305,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
});
let temp =
unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability));
block.and(Place::from(temp))
block.and(PlaceBuilder::from(temp))
}
}
}
Expand Down