Skip to content

Commit be5157b

Browse files
committed
Add an InstSimplify for repetitive array expressions
1 parent fb546ee commit be5157b

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

compiler/rustc_mir_transform/src/instsimplify.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
4848
ctx.simplify_ref_deref(rvalue);
4949
ctx.simplify_ptr_aggregate(rvalue);
5050
ctx.simplify_cast(rvalue);
51+
ctx.simplify_repeated_aggregate(rvalue);
5152
}
5253
_ => {}
5354
}
@@ -68,6 +69,35 @@ struct InstSimplifyContext<'a, 'tcx> {
6869
}
6970

7071
impl<'tcx> InstSimplifyContext<'_, 'tcx> {
72+
/// Transform aggregates like [0, 0, 0, 0, 0] into [0; 5].
73+
/// GVN can also do this optimization, but GVN is only run at mir-opt-level 2 so having this in
74+
/// InstSimplify helps unoptimized builds.
75+
fn simplify_repeated_aggregate(&self, rvalue: &mut Rvalue<'tcx>) {
76+
let Rvalue::Aggregate(box AggregateKind::Array(_), fields) = rvalue else {
77+
return;
78+
};
79+
if fields.len() < 5 {
80+
return;
81+
}
82+
let first = &fields[rustc_abi::FieldIdx::ZERO];
83+
let Operand::Constant(first) = first else {
84+
return;
85+
};
86+
let Ok(first_val) = first.const_.eval(self.tcx, self.typing_env, first.span) else {
87+
return;
88+
};
89+
if fields.iter().all(|field| {
90+
let Operand::Constant(field) = field else {
91+
return false;
92+
};
93+
let field = field.const_.eval(self.tcx, self.typing_env, field.span);
94+
field == Ok(first_val)
95+
}) {
96+
let len = ty::Const::from_target_usize(self.tcx, fields.len().try_into().unwrap());
97+
*rvalue = Rvalue::Repeat(Operand::Constant(first.clone()), len);
98+
}
99+
}
100+
71101
/// Transform boolean comparisons into logical operations.
72102
fn simplify_bool_cmp(&self, rvalue: &mut Rvalue<'tcx>) {
73103
match rvalue {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
- // MIR for `make_array` before InstSimplify-after-simplifycfg
2+
+ // MIR for `make_array` after InstSimplify-after-simplifycfg
3+
4+
fn make_array() -> [u8; 5] {
5+
let mut _0: [u8; 5];
6+
7+
bb0: {
8+
- _0 = [const 0_u8, const 0_u8, const 0_u8, const 0_u8, const 0_u8];
9+
+ _0 = [const 0_u8; 5];
10+
return;
11+
}
12+
}
13+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ test-mir-pass: InstSimplify-after-simplifycfg
2+
#![crate_type = "lib"]
3+
4+
// EMIT_MIR aggregate_array.make_array.InstSimplify-after-simplifycfg.diff
5+
pub fn make_array() -> [u8; 5] {
6+
// CHECK-LABEL: fn make_array(
7+
// CHECK-NOT: _0 = [const 0_u8, const 0_u8, const 0_u8, const 0_u8, const 0_u8];
8+
// CHECK: _0 = [const 0_u8; 5];
9+
10+
[0, 0, 0, 0, 0]
11+
}

0 commit comments

Comments
 (0)