Skip to content

Commit 4b24c56

Browse files
committed
Auto merge of #48052 - eddyb:deggregate, r=<try>
rustc_mir: handle all aggregate kinds in, and always run, the deaggregator. This helps with removing`Rvalue::Aggregate` from the MIR, and with enabling more optimizations. r? @nikomatsakis
2 parents 4d2d3fc + b91a7e5 commit 4b24c56

File tree

10 files changed

+114
-109
lines changed

10 files changed

+114
-109
lines changed

src/librustc_mir/transform/deaggregator.rs

+83-92
Original file line numberDiff line numberDiff line change
@@ -21,116 +21,107 @@ impl MirPass for Deaggregator {
2121
tcx: TyCtxt<'a, 'tcx, 'tcx>,
2222
source: MirSource,
2323
mir: &mut Mir<'tcx>) {
24-
let node_path = tcx.item_path_str(source.def_id);
25-
debug!("running on: {:?}", node_path);
26-
// we only run when mir_opt_level > 2
27-
if tcx.sess.opts.debugging_opts.mir_opt_level <= 2 {
28-
return;
29-
}
30-
3124
// Don't run on constant MIR, because trans might not be able to
3225
// evaluate the modified MIR.
3326
// FIXME(eddyb) Remove check after miri is merged.
3427
let id = tcx.hir.as_local_node_id(source.def_id).unwrap();
3528
match (tcx.hir.body_owner_kind(id), source.promoted) {
36-
(hir::BodyOwnerKind::Fn, None) => {},
37-
_ => return
29+
(_, Some(_)) |
30+
(hir::BodyOwnerKind::Const, _) |
31+
(hir::BodyOwnerKind::Static(_), _) => return,
32+
33+
(hir::BodyOwnerKind::Fn, _) => {
34+
if tcx.is_const_fn(source.def_id) {
35+
// Don't run on const functions, as, again, trans might not be able to evaluate
36+
// the optimized IR.
37+
return
38+
}
39+
}
3840
}
39-
// In fact, we might not want to trigger in other cases.
40-
// Ex: when we could use SROA. See issue #35259
4141

42-
for bb in mir.basic_blocks_mut() {
43-
let mut curr: usize = 0;
44-
while let Some(idx) = get_aggregate_statement_index(curr, &bb.statements) {
45-
// do the replacement
46-
debug!("removing statement {:?}", idx);
47-
let src_info = bb.statements[idx].source_info;
48-
let suffix_stmts = bb.statements.split_off(idx+1);
42+
let can_deaggregate = |statement: &Statement| {
43+
if let StatementKind::Assign(_, ref rhs) = statement.kind {
44+
if let Rvalue::Aggregate(ref kind, _) = *rhs {
45+
// FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
46+
if let AggregateKind::Array(_) = **kind {
47+
return false;
48+
}
49+
return true;
50+
}
51+
}
52+
53+
false
54+
};
55+
56+
let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut();
57+
for bb in basic_blocks {
58+
let mut start = 0;
59+
while let Some(i) = bb.statements[start..].iter().position(&can_deaggregate) {
60+
let i = start + i;
61+
62+
// FIXME(eddyb) this is probably more expensive than it should be.
63+
// Ideally we'd move the block's statements all at once.
64+
let suffix_stmts = bb.statements.split_off(i + 1);
4965
let orig_stmt = bb.statements.pop().unwrap();
50-
let (lhs, rhs) = match orig_stmt.kind {
51-
StatementKind::Assign(ref lhs, ref rhs) => (lhs, rhs),
52-
_ => span_bug!(src_info.span, "expected assign, not {:?}", orig_stmt),
53-
};
54-
let (agg_kind, operands) = match rhs {
55-
&Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands),
56-
_ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
66+
let source_info = orig_stmt.source_info;
67+
let (mut lhs, kind, operands) = match orig_stmt.kind {
68+
StatementKind::Assign(lhs, Rvalue::Aggregate(kind, operands))
69+
=> (lhs, kind, operands),
70+
_ => bug!()
5771
};
58-
let (adt_def, variant, substs) = match **agg_kind {
59-
AggregateKind::Adt(adt_def, variant, substs, None)
60-
=> (adt_def, variant, substs),
61-
_ => span_bug!(src_info.span, "expected struct, not {:?}", rhs),
72+
73+
let mut set_discriminant = None;
74+
let active_field_index = match *kind {
75+
AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
76+
if adt_def.is_enum() {
77+
set_discriminant = Some(Statement {
78+
kind: StatementKind::SetDiscriminant {
79+
place: lhs.clone(),
80+
variant_index,
81+
},
82+
source_info,
83+
});
84+
lhs = lhs.downcast(adt_def, variant_index);
85+
}
86+
active_field_index
87+
}
88+
_ => None
6289
};
63-
let n = bb.statements.len();
64-
bb.statements.reserve(n + operands.len() + suffix_stmts.len());
65-
for (i, op) in operands.iter().enumerate() {
66-
let ref variant_def = adt_def.variants[variant];
67-
let ty = variant_def.fields[i].ty(tcx, substs);
68-
let rhs = Rvalue::Use(op.clone());
6990

70-
let lhs_cast = if adt_def.is_enum() {
71-
Place::Projection(Box::new(PlaceProjection {
72-
base: lhs.clone(),
73-
elem: ProjectionElem::Downcast(adt_def, variant),
74-
}))
75-
} else {
76-
lhs.clone()
77-
};
91+
let new_total_count = bb.statements.len() +
92+
operands.len() +
93+
(set_discriminant.is_some() as usize) +
94+
suffix_stmts.len();
95+
bb.statements.reserve(new_total_count);
7896

79-
let lhs_proj = Place::Projection(Box::new(PlaceProjection {
80-
base: lhs_cast,
81-
elem: ProjectionElem::Field(Field::new(i), ty),
82-
}));
83-
let new_statement = Statement {
84-
source_info: src_info,
85-
kind: StatementKind::Assign(lhs_proj, rhs),
97+
for (j, op) in operands.into_iter().enumerate() {
98+
let lhs_field = if let AggregateKind::Array(_) = *kind {
99+
// FIXME(eddyb) `offset` should be u64.
100+
let offset = j as u32;
101+
assert_eq!(offset as usize, j);
102+
lhs.clone().elem(ProjectionElem::ConstantIndex {
103+
offset,
104+
// FIXME(eddyb) `min_length` doesn't appear to be used.
105+
min_length: offset + 1,
106+
from_end: false
107+
})
108+
} else {
109+
let ty = op.ty(local_decls, tcx);
110+
let field = Field::new(active_field_index.unwrap_or(j));
111+
lhs.clone().field(field, ty)
86112
};
87-
debug!("inserting: {:?} @ {:?}", new_statement, idx + i);
88-
bb.statements.push(new_statement);
113+
bb.statements.push(Statement {
114+
source_info,
115+
kind: StatementKind::Assign(lhs_field, Rvalue::Use(op)),
116+
});
89117
}
90118

91-
// if the aggregate was an enum, we need to set the discriminant
92-
if adt_def.is_enum() {
93-
let set_discriminant = Statement {
94-
kind: StatementKind::SetDiscriminant {
95-
place: lhs.clone(),
96-
variant_index: variant,
97-
},
98-
source_info: src_info,
99-
};
100-
bb.statements.push(set_discriminant);
101-
};
119+
// If the aggregate was an enum, we need to set the discriminant.
120+
bb.statements.extend(set_discriminant);
102121

103-
curr = bb.statements.len();
122+
start = bb.statements.len();
104123
bb.statements.extend(suffix_stmts);
105124
}
106125
}
107126
}
108127
}
109-
110-
fn get_aggregate_statement_index<'a, 'tcx, 'b>(start: usize,
111-
statements: &Vec<Statement<'tcx>>)
112-
-> Option<usize> {
113-
for i in start..statements.len() {
114-
let ref statement = statements[i];
115-
let rhs = match statement.kind {
116-
StatementKind::Assign(_, ref rhs) => rhs,
117-
_ => continue,
118-
};
119-
let (kind, operands) = match rhs {
120-
&Rvalue::Aggregate(ref kind, ref operands) => (kind, operands),
121-
_ => continue,
122-
};
123-
let (adt_def, variant) = match **kind {
124-
AggregateKind::Adt(adt_def, variant, _, None) => (adt_def, variant),
125-
_ => continue,
126-
};
127-
if operands.len() == 0 {
128-
// don't deaggregate ()
129-
continue;
130-
}
131-
debug!("getting variant {:?}", variant);
132-
debug!("for adt_def {:?}", adt_def);
133-
return Some(i);
134-
};
135-
None
136-
}

src/librustc_mir/transform/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
255255

256256
// Optimizations begin.
257257
inline::Inline,
258+
259+
// Lowering generator control-flow and variables
260+
// has to happen before we do anything else to them.
261+
generator::StateTransform,
262+
258263
instcombine::InstCombine,
259264
deaggregator::Deaggregator,
260265
copy_prop::CopyPropagation,

src/librustc_mir/transform/simplify.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
4242
use rustc::ty::TyCtxt;
4343
use rustc::mir::*;
4444
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext};
45+
use rustc::session::config::FullDebugInfo;
4546
use std::borrow::Cow;
4647
use transform::{MirPass, MirSource};
4748

@@ -281,16 +282,24 @@ pub struct SimplifyLocals;
281282

282283
impl MirPass for SimplifyLocals {
283284
fn run_pass<'a, 'tcx>(&self,
284-
_: TyCtxt<'a, 'tcx, 'tcx>,
285+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
285286
_: MirSource,
286287
mir: &mut Mir<'tcx>) {
287288
let mut marker = DeclMarker { locals: BitVector::new(mir.local_decls.len()) };
288289
marker.visit_mir(mir);
289290
// Return pointer and arguments are always live
290-
marker.locals.insert(0);
291-
for idx in mir.args_iter() {
292-
marker.locals.insert(idx.index());
291+
marker.locals.insert(RETURN_PLACE.index());
292+
for arg in mir.args_iter() {
293+
marker.locals.insert(arg.index());
293294
}
295+
296+
// We may need to keep dead user variables live for debuginfo.
297+
if tcx.sess.opts.debuginfo == FullDebugInfo {
298+
for local in mir.vars_iter() {
299+
marker.locals.insert(local.index());
300+
}
301+
}
302+
294303
let map = make_local_map(&mut mir.local_decls, marker.locals);
295304
// Update references to all vars and tmps now
296305
LocalUpdater { map: map }.visit_mir(mir);

src/test/codegen/lifetime_start_end.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ pub fn test() {
2828
// CHECK: [[S_b:%[0-9]+]] = bitcast %"core::option::Option<i32>"** %b to i8*
2929
// CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S_b]])
3030

31-
// CHECK: [[S__5:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_5 to i8*
32-
// CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S__5]])
31+
// CHECK: [[S__4:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_4 to i8*
32+
// CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S__4]])
3333

3434
// CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option<i32>"** %b to i8*
3535
// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E_b]])
3636

37-
// CHECK: [[E__5:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_5 to i8*
38-
// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E__5]])
37+
// CHECK: [[E__4:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_4 to i8*
38+
// CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E__4]])
3939
}
4040

4141
let c = 1;

src/test/codegen/match.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub enum E {
1919

2020
// CHECK-LABEL: @exhaustive_match
2121
#[no_mangle]
22-
pub fn exhaustive_match(e: E) {
22+
pub fn exhaustive_match(e: E, unit: ()) {
2323
// CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [
2424
// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]]
2525
// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]]
@@ -31,7 +31,7 @@ pub fn exhaustive_match(e: E) {
3131
// CHECK: [[OTHERWISE]]:
3232
// CHECK-NEXT: unreachable
3333
match e {
34-
E::A => (),
35-
E::B => (),
34+
E::A => unit,
35+
E::B => unit,
3636
}
3737
}

src/test/incremental/hashes/closure_expressions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub fn change_parameter_pattern() {
6464
}
6565

6666
#[cfg(not(cfail1))]
67-
#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, MirOptimized, TypeckTables")]
67+
#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, TypeckTables")]
6868
#[rustc_clean(cfg="cfail3")]
6969
pub fn change_parameter_pattern() {
7070
let _ = |&x: &u32| x;

src/test/incremental/issue-38222.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#![feature(rustc_attrs)]
1919

2020

21-
#![rustc_partition_translated(module="issue_38222-mod1", cfg="rpass2")]
21+
#![rustc_partition_reused(module="issue_38222-mod1", cfg="rpass2")]
2222

2323
// If trans had added a dependency edge to the Krate dep-node, nothing would
2424
// be re-used, so checking that this module was re-used is sufficient.

src/test/mir-opt/copy_propagation_arg.rs

-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ fn main() {
7878
// bb1: {
7979
// StorageDead(_3);
8080
// _1 = const 5u8;
81-
// _0 = ();
8281
// return;
8382
// }
8483
// END rustc.bar.CopyPropagation.before.mir
@@ -100,7 +99,6 @@ fn main() {
10099
// _2 = _1;
101100
// _1 = move _2;
102101
// StorageDead(_2);
103-
// _0 = ();
104102
// return;
105103
// }
106104
// END rustc.baz.CopyPropagation.before.mir

src/test/run-make/sepcomp-cci-copies/Makefile

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
# Check that cross-crate inlined items are inlined in all compilation units
44
# that refer to them, and not in any other compilation units.
5+
# Note that we have to pass `-C codegen-units=6` because up to two CGUs may be
6+
# created for each source module (see `rustc_mir::monomorphize::partitioning`).
57

68
all:
79
$(RUSTC) cci_lib.rs
8-
$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 \
10+
$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=6 \
911
-Z inline-in-all-cgus
1012
[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*cci_fn)" -eq "2" ]

src/test/ui/print_type_sizes/generics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub fn f1<T:Copy>(x: T) {
7272
fn start(_: isize, _: *const *const u8) -> isize {
7373
let _b: Pair<u8> = Pair::new(0, 0);
7474
let _s: Pair<SevenBytes> = Pair::new(SevenBytes::new(), SevenBytes::new());
75-
let _z: ZeroSized = ZeroSized;
75+
let ref _z: ZeroSized = ZeroSized;
7676
f1::<SevenBytes>(SevenBytes::new());
7777
0
7878
}

0 commit comments

Comments
 (0)