--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::ty::TyCtxt;
+use rustc::mir::repr::*;
+use rustc::mir::transform::{MirPass, MirSource, Pass};
+use rustc_data_structures::indexed_vec::Idx;
+use rustc::ty::VariantKind;
+
+pub struct Deaggregator;
+
+impl Pass for Deaggregator {}
+
+impl<'tcx> MirPass<'tcx> for Deaggregator {
+ fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ source: MirSource, mir: &mut Mir<'tcx>) {
+ let node_id = source.item_id();
+ let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
+ debug!("running on: {:?}", node_path);
+ // we only run when mir_opt_level > 1
+ match tcx.sess.opts.debugging_opts.mir_opt_level {
+ Some(0) |
+ Some(1) |
+ None => { return; },
+ _ => {}
+ };
+
+ // Do not trigger on constants. Could be revised in future
+ if let MirSource::Fn(_) = source {} else { return; }
+ // In fact, we might not want to trigger in other cases.
+ // Ex: when we could use SROA. See issue #35259
+
+ let mut curr: usize = 0;
+ for bb in mir.basic_blocks_mut() {
+ let idx = match get_aggregate_statement(curr, &bb.statements) {
+ Some(idx) => idx,
+ None => continue,
+ };
+ // do the replacement
+ debug!("removing statement {:?}", idx);
+ let src_info = bb.statements[idx].source_info;
+ let suffix_stmts = bb.statements.split_off(idx+1);
+ let orig_stmt = bb.statements.pop().unwrap();
+ let StatementKind::Assign(ref lhs, ref rhs) = orig_stmt.kind;
+ let (agg_kind, operands) = match rhs {
+ &Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands),
+ _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
+ };
+ let (adt_def, variant, substs) = match agg_kind {
+ &AggregateKind::Adt(adt_def, variant, substs) => (adt_def, variant, substs),
+ _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs),
+ };
+ let n = bb.statements.len();
+ bb.statements.reserve(n + operands.len() + suffix_stmts.len());
+ for (i, op) in operands.iter().enumerate() {
+ let ref variant_def = adt_def.variants[variant];
+ let ty = variant_def.fields[i].ty(tcx, substs);
+ let rhs = Rvalue::Use(op.clone());
+
+ // since we don't handle enums, we don't need a cast
+ let lhs_cast = lhs.clone();
+
+ // FIXME we cannot deaggregate enums issue: #35186
+
+ let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection {
+ base: lhs_cast,
+ elem: ProjectionElem::Field(Field::new(i), ty),
+ }));
+ let new_statement = Statement {
+ source_info: src_info,
+ kind: StatementKind::Assign(lhs_proj, rhs),
+ };
+ debug!("inserting: {:?} @ {:?}", new_statement, idx + i);
+ bb.statements.push(new_statement);
+ }
+ curr = bb.statements.len();
+ bb.statements.extend(suffix_stmts);
+ }
+ }
+}
+
+fn get_aggregate_statement<'a, 'tcx, 'b>(curr: usize,
+ statements: &Vec<Statement<'tcx>>)
+ -> Option<usize> {
+ for i in curr..statements.len() {
+ let ref statement = statements[i];
+ let StatementKind::Assign(_, ref rhs) = statement.kind;
+ let (kind, operands) = match rhs {
+ &Rvalue::Aggregate(ref kind, ref operands) => (kind, operands),
+ _ => continue,
+ };
+ let (adt_def, variant) = match kind {
+ &AggregateKind::Adt(adt_def, variant, _) => (adt_def, variant),
+ _ => continue,
+ };
+ if operands.len() == 0 || adt_def.variants.len() > 1 {
+ // don't deaggregate ()
+ // don't deaggregate enums ... for now
+ continue;
+ }
+ debug!("getting variant {:?}", variant);
+ debug!("for adt_def {:?}", adt_def);
+ let variant_def = &adt_def.variants[variant];
+ if variant_def.kind == VariantKind::Struct {
+ return Some(i);
+ }
+ };
+ None
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Baz {
+ x: usize,
+ y: f32,
+ z: bool,
+}
+
+fn bar(a: usize) -> Baz {
+ Baz { x: a, y: 0.0, z: false }
+}
+
+fn main() {}
+
+// END RUST SOURCE
+// START rustc.node13.Deaggregator.before.mir
+// bb0: {
+// var0 = arg0; // scope 0 at main.rs:8:8: 8:9
+// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15
+// return = Baz { x: tmp0, y: const F32(0), z: const false }; // scope ...
+// goto -> bb1; // scope 1 at main.rs:8:1: 10:2
+// }
+// END rustc.node13.Deaggregator.before.mir
+// START rustc.node13.Deaggregator.after.mir
+// bb0: {
+// var0 = arg0; // scope 0 at main.rs:8:8: 8:9
+// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15
+// (return.0: usize) = tmp0; // scope 1 at main.rs:9:5: 9:34
+// (return.1: f32) = const F32(0); // scope 1 at main.rs:9:5: 9:34
+// (return.2: bool) = const false; // scope 1 at main.rs:9:5: 9:34
+// goto -> bb1; // scope 1 at main.rs:8:1: 10:2
+// }
+// END rustc.node13.Deaggregator.after.mir
\ No newline at end of file