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

Rollup of 10 pull requests #48615

Merged
merged 20 commits into from
Mar 1, 2018
Merged
Changes from 2 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a47fd3d
make `#[unwind]` attribute specify expectations more clearly
nikomatsakis Feb 20, 2018
566c6ac
add `unwind_attributes` feature
nikomatsakis Feb 22, 2018
56a6828
Implement --remap-path-prefix
jsgf Feb 18, 2018
d9438c3
Add ToString and FromStr impls for Epoch
Manishearth Feb 22, 2018
da9dc05
Allow future-incompat lints to mention an epoch
Manishearth Feb 23, 2018
3eeabe7
Add hardwired lint for dyn trait
Manishearth Feb 23, 2018
bd29696
Add ability for hardwired lints to operate on the diagnostic builder
Manishearth Feb 23, 2018
63168f7
Lint bare traits
Manishearth Feb 23, 2018
177271f
span_bug doesn't work well at this stage, use the session directly
Manishearth Feb 23, 2018
dd67fe1
Silence warning in test
Manishearth Feb 23, 2018
12c7e27
restore Subslice move out from array after elaborate drops and borrowck
mikhail-m1 Feb 19, 2018
0cb3672
Emit parentheses in suggestion for global paths
Manishearth Feb 23, 2018
db6a5ee
Minor grammatical/style fix in docs.
pthariensflame Feb 28, 2018
b9e9b4a
Add std::path::Path::ancestors
teiesti Feb 28, 2018
f59ab8e
Rollup merge of #48355 - mikhail-m1:subslice_pattern_array_drop2, r=n…
Manishearth Feb 28, 2018
fac7d7c
Rollup merge of #48359 - jsgf:remap-path-prefix, r=sanxiyn
Manishearth Feb 28, 2018
1251560
Rollup merge of #48380 - nikomatsakis:issue-48251-master, r=acrichto
Manishearth Feb 28, 2018
6b5519d
Rollup merge of #48420 - teiesti:path_parents, r=BurntSushi
Manishearth Feb 28, 2018
f57835b
Rollup merge of #48461 - Manishearth:epoch-dyn-trait, r=nmatsakis
Manishearth Feb 28, 2018
b2b9707
Rollup merge of #48603 - pthariensflame:patch-1, r=frewsxcv
Manishearth Feb 28, 2018
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
1 change: 1 addition & 0 deletions src/librustc_mir/transform/mod.rs
Original file line number Diff line number Diff line change
@@ -257,6 +257,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx


// Optimizations begin.
uniform_array_move_out::RestoreSubsliceArrayMoveOut,
inline::Inline,

// Lowering generator control-flow and variables
198 changes: 187 additions & 11 deletions src/librustc_mir/transform/uniform_array_move_out.rs
Original file line number Diff line number Diff line change
@@ -34,15 +34,15 @@
// and mir statement _11 = move _2[-1 of 1]; replaced by:
// _11 = move _2[2 of 3];
//
// FIXME: convert to Subslice back for performance reason
// FIXME: integrate this transformation to the mir build

use rustc::ty;
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::visit::Visitor;
use rustc::mir::visit::{Visitor, PlaceContext};
use transform::{MirPass, MirSource};
use util::patch::MirPatch;
use rustc_data_structures::indexed_vec::{IndexVec};

pub struct UniformArrayMoveOut;

@@ -67,12 +67,12 @@ struct UniformArrayMoveOutVisitor<'a, 'tcx: 'a> {
}

impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
fn visit_statement(&mut self,
block: BasicBlock,
statement: &Statement<'tcx>,
location: Location) {
if let StatementKind::Assign(ref dst_place,
Rvalue::Use(Operand::Move(ref src_place))) = statement.kind {
fn visit_assign(&mut self,
block: BasicBlock,
dst_place: &Place<'tcx>,
rvalue: &Rvalue<'tcx>,
location: Location) {
if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
if let Place::Projection(ref proj) = *src_place {
if let ProjectionElem::ConstantIndex{offset: _,
min_length: _,
@@ -92,7 +92,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
}
}
}
return self.super_statement(block, statement, location);
self.super_assign(block, dst_place, rvalue, location)
}
}

@@ -104,7 +104,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
item_ty: &'tcx ty::TyS<'tcx>,
size: u32) {
match proj.elem {
// uniform _10 = move _2[:-1];
// uniforms statements like_10 = move _2[:-1];
ProjectionElem::Subslice{from, to} => {
self.patch.make_nop(location);
let temps : Vec<_> = (from..(size-to)).map(|i| {
@@ -133,7 +133,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
self.patch.add_statement(location, StatementKind::StorageDead(temp));
}
}
// _11 = move _2[-1 of 1];
// uniforms statements like _11 = move _2[-1 of 1];
ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
self.patch.make_nop(location);
self.patch.add_assign(location,
@@ -151,3 +151,179 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
}
}
}

// Restore Subslice move out after analysis
// Example:
//
// next statements:
// StorageLive(_12);
// _12 = move _2[0 of 3];
// StorageLive(_13);
// _13 = move _2[1 of 3];
// _10 = [move _12, move _13]
// StorageDead(_12);
// StorageDead(_13);
//
// replaced by _10 = move _2[:-1];

pub struct RestoreSubsliceArrayMoveOut;

impl MirPass for RestoreSubsliceArrayMoveOut {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource,
mir: &mut Mir<'tcx>) {
let mut patch = MirPatch::new(mir);
{
let mut visitor = RestoreDataCollector {
locals_use: IndexVec::from_elem(LocalUse::new(), &mir.local_decls),
candidates: vec![],
};
visitor.visit_mir(mir);

for candidate in &visitor.candidates {
let statement = &mir[candidate.block].statements[candidate.statement_index];
if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind {
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
let items : Vec<_> = items.iter().map(|item| {
if let Operand::Move(Place::Local(local)) = item {
let local_use = &visitor.locals_use[*local];
let opt_index_and_place = Self::try_get_item_source(local_use, mir);
// each local should be used twice:
// in assign and in aggregate statments
if local_use.use_count == 2 && opt_index_and_place.is_some() {
let (index, src_place) = opt_index_and_place.unwrap();
return Some((local_use, index, src_place));
}
}
None
}).collect();

let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
let opt_size = opt_src_place.and_then(|src_place| {
let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
if let ty::TyArray(_, ref size_o) = src_ty.sty {
size_o.val.to_const_int().and_then(|v| v.to_u64())
} else {
None
}
});
Self::check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
}
}
}
}
patch.apply(mir);
}
}

impl RestoreSubsliceArrayMoveOut {
// Checks that source has size, all locals are inited from same source place and
// indices is an integer interval. If all checks pass do the replacent.
// items are Vec<Option<LocalUse, index in source array, source place for init local>>
fn check_and_patch<'tcx>(candidate: Location,
items: &Vec<Option<(&LocalUse, u32, &Place<'tcx>)>>,
opt_size: Option<u64>,
patch: &mut MirPatch<'tcx>,
dst_place: &Place<'tcx>) {
let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);

if opt_size.is_some() && items.iter().all(
|l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) {

let indicies: Vec<_> = items.iter().map(|x| x.unwrap().1).collect();
for i in 1..indicies.len() {
if indicies[i - 1] + 1 != indicies[i] {
return;
}
}

let min = *indicies.first().unwrap();
let max = *indicies.last().unwrap();

for item in items {
let locals_use = item.unwrap().0;
patch.make_nop(locals_use.alive.unwrap());
patch.make_nop(locals_use.dead.unwrap());
patch.make_nop(locals_use.first_use.unwrap());
}
patch.make_nop(candidate);
let size = opt_size.unwrap() as u32;
patch.add_assign(candidate,
dst_place.clone(),
Rvalue::Use(
Operand::Move(
Place::Projection(box PlaceProjection{
base: opt_src_place.unwrap().clone(),
elem: ProjectionElem::Subslice{
from: min, to: size - max - 1}}))));
}
}

fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse,
mir: &'a Mir<'tcx>) -> Option<(u32, &'a Place<'tcx>)> {
if let Some(location) = local_use.first_use {
let block = &mir[location.block];
if block.statements.len() > location.statement_index {
let statement = &block.statements[location.statement_index];
if let StatementKind::Assign(
Place::Local(_),
Rvalue::Use(Operand::Move(Place::Projection(box PlaceProjection{
ref base, elem: ProjectionElem::ConstantIndex{
offset, min_length: _, from_end: false}})))) = statement.kind {
return Some((offset, base))
}
}
}
None
}
}

#[derive(Copy, Clone, Debug)]
struct LocalUse {
alive: Option<Location>,
dead: Option<Location>,
use_count: u32,
first_use: Option<Location>,
}

impl LocalUse {
pub fn new() -> Self {
LocalUse{alive: None, dead: None, use_count: 0, first_use: None}
}
}

struct RestoreDataCollector {
locals_use: IndexVec<Local, LocalUse>,
candidates: Vec<Location>,
}

impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
fn visit_assign(&mut self,
block: BasicBlock,
place: &Place<'tcx>,
rvalue: &Rvalue<'tcx>,
location: Location) {
if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue {
self.candidates.push(location);
}
self.super_assign(block, place, rvalue, location)
}

fn visit_local(&mut self,
local: &Local,
context: PlaceContext<'tcx>,
location: Location) {
let local_use = &mut self.locals_use[*local];
match context {
PlaceContext::StorageLive => local_use.alive = Some(location),
PlaceContext::StorageDead => local_use.dead = Some(location),
_ => {
local_use.use_count += 1;
if local_use.first_use.is_none() {
local_use.first_use = Some(location);
}
}
}
}
}
25 changes: 25 additions & 0 deletions src/test/mir-opt/uniform_array_move_out.rs
Original file line number Diff line number Diff line change
@@ -57,3 +57,28 @@ fn main() {
// nop;
// _0 = ();
// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir

// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
// StorageLive(_6);
// StorageLive(_7);
// _7 = move _1[0 of 2];
// StorageLive(_8);
// _8 = move _1[1 of 2];
// _6 = [move _7, move _8];
// StorageDead(_7);
// StorageDead(_8);
// _0 = ();
// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir

// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
// StorageLive(_6);
// nop;
// nop;
// nop;
// nop;
// _6 = move _1[0:];
// nop;
// nop;
// nop;
// _0 = ();
// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir