Skip to content

Commit b85bd51

Browse files
committed
Auto merge of #47926 - mikhail-m1:subslice_pattern_array_drop2, r=nikomatsakis
add transform for uniform array move out reworked second step for fix #34708 previous try #46686 r? @nikomatsakis
2 parents 507a46a + 31253d5 commit b85bd51

File tree

6 files changed

+302
-1
lines changed

6 files changed

+302
-1
lines changed

src/librustc_mir/transform/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub mod copy_prop;
4444
pub mod generator;
4545
pub mod inline;
4646
pub mod lower_128bit;
47+
pub mod uniform_array_move_out;
4748

4849
pub(crate) fn provide(providers: &mut Providers) {
4950
self::qualify_consts::provide(providers);
@@ -197,6 +198,7 @@ fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea
197198
simplify::SimplifyCfg::new("initial"),
198199
type_check::TypeckMir,
199200
rustc_peek::SanityCheck,
201+
uniform_array_move_out::UniformArrayMoveOut,
200202
];
201203
tcx.alloc_steal_mir(mir)
202204
}
@@ -253,6 +255,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
253255

254256
lower_128bit::Lower128Bit,
255257

258+
256259
// Optimizations begin.
257260
inline::Inline,
258261
instcombine::InstCombine,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This pass converts move out from array by Subslice and
12+
// ConstIndex{.., from_end: true} to ConstIndex move out(s) from begin
13+
// of array. It allows detect error by mir borrowck and elaborate
14+
// drops for array without additional work.
15+
//
16+
// Example:
17+
//
18+
// let a = [ box 1,box 2, box 3];
19+
// if b {
20+
// let [_a.., _] = a;
21+
// } else {
22+
// let [.., _b] = a;
23+
// }
24+
//
25+
// mir statement _10 = move _2[:-1]; replaced by:
26+
// StorageLive(_12);
27+
// _12 = move _2[0 of 3];
28+
// StorageLive(_13);
29+
// _13 = move _2[1 of 3];
30+
// _10 = [move _12, move _13]
31+
// StorageDead(_12);
32+
// StorageDead(_13);
33+
//
34+
// and mir statement _11 = move _2[-1 of 1]; replaced by:
35+
// _11 = move _2[2 of 3];
36+
//
37+
// FIXME: convert to Subslice back for performance reason
38+
// FIXME: integrate this transformation to the mir build
39+
40+
use rustc::ty;
41+
use rustc::ty::TyCtxt;
42+
use rustc::mir::*;
43+
use rustc::mir::visit::Visitor;
44+
use transform::{MirPass, MirSource};
45+
use util::patch::MirPatch;
46+
47+
pub struct UniformArrayMoveOut;
48+
49+
impl MirPass for UniformArrayMoveOut {
50+
fn run_pass<'a, 'tcx>(&self,
51+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
52+
_src: MirSource,
53+
mir: &mut Mir<'tcx>) {
54+
let mut patch = MirPatch::new(mir);
55+
{
56+
let mut visitor = UniformArrayMoveOutVisitor{mir, patch: &mut patch, tcx};
57+
visitor.visit_mir(mir);
58+
}
59+
patch.apply(mir);
60+
}
61+
}
62+
63+
struct UniformArrayMoveOutVisitor<'a, 'tcx: 'a> {
64+
mir: &'a Mir<'tcx>,
65+
patch: &'a mut MirPatch<'tcx>,
66+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
67+
}
68+
69+
impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
70+
fn visit_statement(&mut self,
71+
block: BasicBlock,
72+
statement: &Statement<'tcx>,
73+
location: Location) {
74+
if let StatementKind::Assign(ref dst_place,
75+
Rvalue::Use(Operand::Move(ref src_place))) = statement.kind {
76+
if let Place::Projection(ref proj) = *src_place {
77+
if let ProjectionElem::ConstantIndex{offset: _,
78+
min_length: _,
79+
from_end: false} = proj.elem {
80+
// no need to transformation
81+
} else {
82+
let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
83+
if let ty::TyArray(item_ty, const_size) = place_ty.sty {
84+
if let Some(size) = const_size.val.to_const_int().and_then(|v| v.to_u64()) {
85+
assert!(size <= (u32::max_value() as u64),
86+
"unform array move out doesn't supported
87+
for array bigger then u32");
88+
self.uniform(location, dst_place, proj, item_ty, size as u32);
89+
}
90+
}
91+
92+
}
93+
}
94+
}
95+
return self.super_statement(block, statement, location);
96+
}
97+
}
98+
99+
impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
100+
fn uniform(&mut self,
101+
location: Location,
102+
dst_place: &Place<'tcx>,
103+
proj: &PlaceProjection<'tcx>,
104+
item_ty: &'tcx ty::TyS<'tcx>,
105+
size: u32) {
106+
match proj.elem {
107+
// uniform _10 = move _2[:-1];
108+
ProjectionElem::Subslice{from, to} => {
109+
self.patch.make_nop(location);
110+
let temps : Vec<_> = (from..(size-to)).map(|i| {
111+
let temp = self.patch.new_temp(item_ty, self.mir.source_info(location).span);
112+
self.patch.add_statement(location, StatementKind::StorageLive(temp));
113+
self.patch.add_assign(location,
114+
Place::Local(temp),
115+
Rvalue::Use(
116+
Operand::Move(
117+
Place::Projection(box PlaceProjection{
118+
base: proj.base.clone(),
119+
elem: ProjectionElem::ConstantIndex{
120+
offset: i,
121+
min_length: size,
122+
from_end: false}
123+
}))));
124+
temp
125+
}).collect();
126+
self.patch.add_assign(location,
127+
dst_place.clone(),
128+
Rvalue::Aggregate(box AggregateKind::Array(item_ty),
129+
temps.iter().map(
130+
|x| Operand::Move(Place::Local(*x))).collect()
131+
));
132+
for temp in temps {
133+
self.patch.add_statement(location, StatementKind::StorageDead(temp));
134+
}
135+
}
136+
// _11 = move _2[-1 of 1];
137+
ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
138+
self.patch.make_nop(location);
139+
self.patch.add_assign(location,
140+
dst_place.clone(),
141+
Rvalue::Use(
142+
Operand::Move(
143+
Place::Projection(box PlaceProjection{
144+
base: proj.base.clone(),
145+
elem: ProjectionElem::ConstantIndex{
146+
offset: size - offset,
147+
min_length: size,
148+
from_end: false }}))));
149+
}
150+
_ => {}
151+
}
152+
}
153+
}

src/librustc_mir/util/patch.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub struct MirPatch<'tcx> {
2323
new_locals: Vec<LocalDecl<'tcx>>,
2424
resume_block: BasicBlock,
2525
next_local: usize,
26+
make_nop: Vec<Location>,
2627
}
2728

2829
impl<'tcx> MirPatch<'tcx> {
@@ -33,7 +34,8 @@ impl<'tcx> MirPatch<'tcx> {
3334
new_statements: vec![],
3435
new_locals: vec![],
3536
next_local: mir.local_decls.len(),
36-
resume_block: START_BLOCK
37+
resume_block: START_BLOCK,
38+
make_nop: vec![]
3739
};
3840

3941
// make sure the MIR we create has a resume block. It is
@@ -131,7 +133,15 @@ impl<'tcx> MirPatch<'tcx> {
131133
self.add_statement(loc, StatementKind::Assign(place, rv));
132134
}
133135

136+
pub fn make_nop(&mut self, loc: Location) {
137+
self.make_nop.push(loc);
138+
}
139+
134140
pub fn apply(self, mir: &mut Mir<'tcx>) {
141+
debug!("MirPatch: make nops at: {:?}", self.make_nop);
142+
for loc in self.make_nop {
143+
mir.make_statement_nop(loc);
144+
}
135145
debug!("MirPatch: {:?} new temps, starting from index {}: {:?}",
136146
self.new_locals.len(), mir.local_decls.len(), self.new_locals);
137147
debug!("MirPatch: {} new blocks, starting from index {}",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: ast mir
12+
//[mir]compile-flags: -Z borrowck=mir
13+
14+
#![feature(box_syntax, slice_patterns, advanced_slice_patterns)]
15+
16+
fn move_out_from_begin_and_end() {
17+
let a = [box 1, box 2];
18+
let [_, _x] = a;
19+
let [.., _y] = a; //[ast]~ ERROR [E0382]
20+
//[mir]~^ ERROR [E0382]
21+
}
22+
23+
fn move_out_by_const_index_and_subslice() {
24+
let a = [box 1, box 2];
25+
let [_x, _] = a;
26+
let [_y..] = a; //[ast]~ ERROR [E0382]
27+
//[mir]~^ ERROR [E0382]
28+
}
29+
30+
fn main() {}
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(box_syntax, slice_patterns, advanced_slice_patterns)]
12+
13+
fn move_out_from_end() {
14+
let a = [box 1, box 2];
15+
let [.., _y] = a;
16+
}
17+
18+
fn move_out_by_subslice() {
19+
let a = [box 1, box 2];
20+
let [_y..] = a;
21+
}
22+
23+
fn main() {
24+
move_out_by_subslice();
25+
move_out_from_end();
26+
}
27+
28+
// END RUST SOURCE
29+
30+
// START rustc.move_out_from_end.UniformArrayMoveOut.before.mir
31+
// StorageLive(_6);
32+
// _6 = move _1[-1 of 1];
33+
// _0 = ();
34+
// END rustc.move_out_from_end.UniformArrayMoveOut.before.mir
35+
36+
// START rustc.move_out_from_end.UniformArrayMoveOut.after.mir
37+
// StorageLive(_6);
38+
// _6 = move _1[1 of 2];
39+
// nop;
40+
// _0 = ();
41+
// END rustc.move_out_from_end.UniformArrayMoveOut.after.mir
42+
43+
// START rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir
44+
// StorageLive(_6);
45+
// _6 = move _1[0:];
46+
// END rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir
47+
48+
// START rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
49+
// StorageLive(_6);
50+
// StorageLive(_7);
51+
// _7 = move _1[0 of 2];
52+
// StorageLive(_8);
53+
// _8 = move _1[1 of 2];
54+
// _6 = [move _7, move _8];
55+
// StorageDead(_7);
56+
// StorageDead(_8);
57+
// nop;
58+
// _0 = ();
59+
// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir

src/test/run-pass/dynamic-drop.rs

+46
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,43 @@ fn slice_pattern_one_of(a: &Allocator, i: usize) {
225225
};
226226
}
227227

228+
fn subslice_pattern_from_end(a: &Allocator, arg: bool) {
229+
let a = [a.alloc(), a.alloc(), a.alloc()];
230+
if arg {
231+
let[.., _x, _] = a;
232+
} else {
233+
let[_, _y..] = a;
234+
}
235+
}
236+
237+
fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) {
238+
let a = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()];
239+
if arg2 {
240+
drop(a);
241+
return;
242+
}
243+
244+
if arg {
245+
let[.., _x, _] = a;
246+
} else {
247+
let[_, _y..] = a;
248+
}
249+
}
250+
251+
fn slice_pattern_reassign(a: &Allocator) {
252+
let mut ar = [a.alloc(), a.alloc()];
253+
let[_, _x] = ar;
254+
ar = [a.alloc(), a.alloc()];
255+
let[.., _y] = ar;
256+
}
257+
258+
fn subslice_pattern_reassign(a: &Allocator) {
259+
let mut ar = [a.alloc(), a.alloc(), a.alloc()];
260+
let[_, _, _x] = ar;
261+
ar = [a.alloc(), a.alloc(), a.alloc()];
262+
let[_, _y..] = ar;
263+
}
264+
228265
fn run_test<F>(mut f: F)
229266
where F: FnMut(&Allocator)
230267
{
@@ -303,5 +340,14 @@ fn main() {
303340
run_test(|a| slice_pattern_one_of(a, 2));
304341
run_test(|a| slice_pattern_one_of(a, 3));
305342

343+
run_test(|a| subslice_pattern_from_end(a, true));
344+
run_test(|a| subslice_pattern_from_end(a, false));
345+
run_test(|a| subslice_pattern_from_end_with_drop(a, true, true));
346+
run_test(|a| subslice_pattern_from_end_with_drop(a, true, false));
347+
run_test(|a| subslice_pattern_from_end_with_drop(a, false, true));
348+
run_test(|a| subslice_pattern_from_end_with_drop(a, false, false));
349+
run_test(|a| slice_pattern_reassign(a));
350+
run_test(|a| subslice_pattern_reassign(a));
351+
306352
run_test_nopanic(|a| union1(a));
307353
}

0 commit comments

Comments
 (0)