Skip to content

Commit 62cdbea

Browse files
committed
deaggregate structs to enable further optimization
1 parent 29abe5e commit 62cdbea

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

src/librustc_driver/driver.rs

+2
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,8 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
994994
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
995995
passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops"));
996996

997+
passes.push_pass(box mir::transform::deaggregator::Deaggregator);
998+
997999
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
9981000
passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans"));
9991001

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2016 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+
use rustc::ty::TyCtxt;
12+
use rustc::mir::repr::*;
13+
use rustc::mir::transform::{MirPass, MirSource, Pass};
14+
use rustc_data_structures::indexed_vec::Idx;
15+
use rustc::ty::VariantKind;
16+
17+
pub struct Deaggregator;
18+
19+
impl Pass for Deaggregator {}
20+
21+
impl<'tcx> MirPass<'tcx> for Deaggregator {
22+
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
23+
source: MirSource, mir: &mut Mir<'tcx>) {
24+
let node_id = source.item_id();
25+
let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
26+
debug!("running on: {:?}", node_path);
27+
// we only run when mir_opt_level > 1
28+
match tcx.sess.opts.debugging_opts.mir_opt_level {
29+
Some(0) |
30+
Some(1) |
31+
None => { return; },
32+
_ => {}
33+
};
34+
if let MirSource::Fn(_) = source {} else { return; }
35+
36+
let mut curr: usize = 0;
37+
for bb in mir.basic_blocks_mut() {
38+
while let Some(idx) = get_aggregate_statement(curr, &bb.statements) {
39+
// do the replacement
40+
debug!("removing statement {:?}", idx);
41+
let src_info = bb.statements[idx].source_info;
42+
let mut suffix_stmts = bb.statements.split_off(idx);
43+
let orig_stmt = suffix_stmts.remove(0);
44+
let StatementKind::Assign(ref lhs, ref rhs) = orig_stmt.kind;
45+
if let &Rvalue::Aggregate(ref agg_kind, ref operands) = rhs {
46+
if let &AggregateKind::Adt(adt_def, variant, substs) = agg_kind {
47+
let n = bb.statements.len();
48+
bb.statements.reserve(n + operands.len() + suffix_stmts.len());
49+
for (i, op) in operands.iter().enumerate() {
50+
let ref variant_def = adt_def.variants[variant];
51+
let ty = variant_def.fields[variant].ty(tcx, substs);
52+
let rhs = Rvalue::Use(op.clone());
53+
54+
// since we don't handle enums, we don't need a cast
55+
let lhs_cast = lhs.clone();
56+
57+
// if we handled enums:
58+
// let lhs_cast = if adt_def.variants.len() > 1 {
59+
// Lvalue::Projection(Box::new(LvalueProjection {
60+
// base: ai.lhs.clone(),
61+
// elem: ProjectionElem::Downcast(ai.adt_def, ai.variant),
62+
// }))
63+
// } else {
64+
// lhs_cast
65+
// };
66+
67+
let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection {
68+
base: lhs_cast,
69+
elem: ProjectionElem::Field(Field::new(i), ty),
70+
}));
71+
let new_statement = Statement {
72+
source_info: src_info,
73+
kind: StatementKind::Assign(lhs_proj, rhs),
74+
};
75+
debug!("inserting: {:?} @ {:?}", new_statement, idx + i);
76+
bb.statements.push(new_statement);
77+
}
78+
curr = bb.statements.len();
79+
bb.statements.extend(suffix_stmts);
80+
}
81+
}
82+
}
83+
}
84+
}
85+
}
86+
87+
fn get_aggregate_statement<'a, 'tcx, 'b>(curr: usize,
88+
statements: &Vec<Statement<'tcx>>)
89+
-> Option<usize> {
90+
for i in curr..statements.len() {
91+
let ref statement = statements[i];
92+
let StatementKind::Assign(_, ref rhs) = statement.kind;
93+
if let &Rvalue::Aggregate(ref kind, ref operands) = rhs {
94+
if let &AggregateKind::Adt(adt_def, variant, _) = kind {
95+
if operands.len() > 0 { // don't deaggregate ()
96+
if adt_def.variants.len() > 1 {
97+
// only deaggrate structs for now
98+
continue;
99+
}
100+
debug!("getting variant {:?}", variant);
101+
debug!("for adt_def {:?}", adt_def);
102+
let variant_def = &adt_def.variants[variant];
103+
if variant_def.kind == VariantKind::Struct {
104+
return Some(i);
105+
}
106+
}
107+
}
108+
}
109+
};
110+
None
111+
}

src/librustc_mir/transform/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ pub mod add_call_guards;
1717
pub mod promote_consts;
1818
pub mod qualify_consts;
1919
pub mod dump_mir;
20+
pub mod deaggregator;

0 commit comments

Comments
 (0)