1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use rustc::hir;
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc_data_structures::indexed_vec::Idx;
use transform::{MirPass, MirSource};
pub struct Deaggregator;
impl MirPass for Deaggregator {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
mir: &mut Mir<'tcx>) {
let node_path = tcx.item_path_str(source.def_id);
debug!("running on: {:?}", node_path);
if tcx.sess.opts.debugging_opts.mir_opt_level <= 2 {
return;
}
let id = tcx.hir.as_local_node_id(source.def_id).unwrap();
match (tcx.hir.body_owner_kind(id), source.promoted) {
(hir::BodyOwnerKind::Fn, None) => {},
_ => return
}
for bb in mir.basic_blocks_mut() {
let mut curr: usize = 0;
while let Some(idx) = get_aggregate_statement_index(curr, &bb.statements) {
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 (lhs, rhs) = match orig_stmt.kind {
StatementKind::Assign(ref lhs, ref rhs) => (lhs, rhs),
_ => span_bug!(src_info.span, "expected assign, not {:?}", orig_stmt),
};
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, None)
=> (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());
let lhs_cast = if adt_def.is_enum() {
Place::Projection(Box::new(PlaceProjection {
base: lhs.clone(),
elem: ProjectionElem::Downcast(adt_def, variant),
}))
} else {
lhs.clone()
};
let lhs_proj = Place::Projection(Box::new(PlaceProjection {
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);
}
if adt_def.is_enum() {
let set_discriminant = Statement {
kind: StatementKind::SetDiscriminant {
place: lhs.clone(),
variant_index: variant,
},
source_info: src_info,
};
bb.statements.push(set_discriminant);
};
curr = bb.statements.len();
bb.statements.extend(suffix_stmts);
}
}
}
}
fn get_aggregate_statement_index<'a, 'tcx, 'b>(start: usize,
statements: &Vec<Statement<'tcx>>)
-> Option<usize> {
for i in start..statements.len() {
let ref statement = statements[i];
let rhs = match statement.kind {
StatementKind::Assign(_, ref rhs) => rhs,
_ => continue,
};
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, _, None) => (adt_def, variant),
_ => continue,
};
if operands.len() == 0 {
continue;
}
debug!("getting variant {:?}", variant);
debug!("for adt_def {:?}", adt_def);
return Some(i);
};
None
}