diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 7ed250e94c52f..f721cdf714dca 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -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,
instcombine::InstCombine,
deaggregator::Deaggregator,
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
index 0db5ecf0eb270..e46de17047986 100644
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ b/src/librustc_mir/transform/uniform_array_move_out.rs
@@ -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