Extract simplify_aggregate.

This commit is contained in:
Camille GILLOT 2023-05-21 12:59:38 +00:00
parent 23d4857080
commit 80a5e8522d
4 changed files with 198 additions and 27 deletions

View File

@ -682,33 +682,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
Value::Repeat(op, amount)
}
Rvalue::NullaryOp(op, ty) => Value::NullaryOp(op, ty),
Rvalue::Aggregate(box ref kind, ref mut fields) => {
let (ty, variant_index) = match *kind {
// For empty arrays, we have not mean to recover the type. They are ZSTs
// anyway, so return them as such.
AggregateKind::Array(..) | AggregateKind::Tuple if fields.is_empty() => {
return Some(self.insert(Value::Constant(Const::zero_sized(
rvalue.ty(self.local_decls, self.tcx),
))));
}
AggregateKind::Array(..) => (AggregateTy::Array, FIRST_VARIANT),
AggregateKind::Tuple => (AggregateTy::Tuple, FIRST_VARIANT),
AggregateKind::Closure(did, substs)
| AggregateKind::Coroutine(did, substs, _) => {
(AggregateTy::Def(did, substs), FIRST_VARIANT)
}
AggregateKind::Adt(did, variant_index, substs, _, None) => {
(AggregateTy::Def(did, substs), variant_index)
}
// Do not track unions.
AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
};
let fields: Option<Vec<_>> = fields
.iter_mut()
.map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque()))
.collect();
Value::Aggregate(ty, variant_index, fields?)
}
Rvalue::Aggregate(..) => self.simplify_aggregate(rvalue, location)?,
Rvalue::Ref(_, borrow_kind, ref mut place) => {
self.simplify_place_projection(place, location);
return self.new_pointer(*place, AddressKind::Ref(borrow_kind));
@ -769,6 +743,61 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
None
}
fn simplify_aggregate(
&mut self,
rvalue: &mut Rvalue<'tcx>,
location: Location,
) -> Option<Value<'tcx>> {
let Rvalue::Aggregate(box ref kind, ref mut fields) = *rvalue else { bug!() };
let tcx = self.tcx;
if fields.is_empty() {
let is_zst = match *kind {
AggregateKind::Array(..) | AggregateKind::Tuple | AggregateKind::Closure(..) => {
true
}
// Only enums can be non-ZST.
AggregateKind::Adt(did, ..) => tcx.def_kind(did) != DefKind::Enum,
// Coroutines are never ZST, as they at least contain the implicit states.
AggregateKind::Coroutine(..) => false,
};
if is_zst {
let ty = rvalue.ty(self.local_decls, tcx);
let value = Value::Constant(Const::zero_sized(ty));
return Some(value);
}
}
let (ty, variant_index) = match *kind {
AggregateKind::Array(..) => {
assert!(!fields.is_empty());
(AggregateTy::Array, FIRST_VARIANT)
}
AggregateKind::Tuple => {
assert!(!fields.is_empty());
(AggregateTy::Tuple, FIRST_VARIANT)
}
AggregateKind::Closure(did, substs) | AggregateKind::Coroutine(did, substs, _) => {
(AggregateTy::Def(did, substs), FIRST_VARIANT)
}
AggregateKind::Adt(did, variant_index, substs, _, None) => {
(AggregateTy::Def(did, substs), variant_index)
}
// Do not track unions.
AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
};
let fields: Option<Vec<_>> = fields
.iter_mut()
.map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque()))
.collect();
let fields = fields?;
let value = Value::Aggregate(ty, variant_index, fields);
Some(value)
}
}
fn op_to_prop_const<'tcx>(

View File

@ -0,0 +1,66 @@
- // MIR for `aggregates` before GVN
+ // MIR for `aggregates` after GVN
fn aggregates() -> () {
let mut _0: ();
let _1: S<[u8; 0]>;
let mut _2: [u8; 0];
let mut _4: [u16; 0];
let mut _6: ();
let mut _8: ();
scope 1 {
debug a_array => _1;
let _3: S<[u16; 0]>;
scope 2 {
debug b_array => _3;
let _5: S<()>;
scope 3 {
debug a_tuple => _5;
let _7: S<()>;
scope 4 {
debug b_tuple => _7;
}
}
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = [];
- _1 = S::<[u8; 0]>(move _2);
+ _2 = const [];
+ _1 = const S::<[u8; 0]>([]);
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
- _4 = [];
- _3 = S::<[u16; 0]>(move _4);
+ _4 = const [];
+ _3 = const S::<[u16; 0]>([]);
StorageDead(_4);
StorageLive(_5);
- StorageLive(_6);
- _6 = ();
- _5 = S::<()>(move _6);
- StorageDead(_6);
+ nop;
+ _6 = const ();
+ _5 = const S::<()>(());
+ nop;
StorageLive(_7);
StorageLive(_8);
- _8 = ();
- _7 = S::<()>(move _8);
+ _8 = const ();
+ _7 = const S::<()>(());
StorageDead(_8);
_0 = const ();
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);
StorageDead(_1);
return;
}
}

View File

@ -0,0 +1,66 @@
- // MIR for `aggregates` before GVN
+ // MIR for `aggregates` after GVN
fn aggregates() -> () {
let mut _0: ();
let _1: S<[u8; 0]>;
let mut _2: [u8; 0];
let mut _4: [u16; 0];
let mut _6: ();
let mut _8: ();
scope 1 {
debug a_array => _1;
let _3: S<[u16; 0]>;
scope 2 {
debug b_array => _3;
let _5: S<()>;
scope 3 {
debug a_tuple => _5;
let _7: S<()>;
scope 4 {
debug b_tuple => _7;
}
}
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = [];
- _1 = S::<[u8; 0]>(move _2);
+ _2 = const [];
+ _1 = const S::<[u8; 0]>([]);
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
- _4 = [];
- _3 = S::<[u16; 0]>(move _4);
+ _4 = const [];
+ _3 = const S::<[u16; 0]>([]);
StorageDead(_4);
StorageLive(_5);
- StorageLive(_6);
- _6 = ();
- _5 = S::<()>(move _6);
- StorageDead(_6);
+ nop;
+ _6 = const ();
+ _5 = const S::<()>(());
+ nop;
StorageLive(_7);
StorageLive(_8);
- _8 = ();
- _7 = S::<()>(move _8);
+ _8 = const ();
+ _7 = const S::<()>(());
StorageDead(_8);
_0 = const ();
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);
StorageDead(_1);
return;
}
}

View File

@ -231,6 +231,14 @@ fn slices() {
assert_eq!(s.as_ptr(), u.as_ptr());
}
fn aggregates() {
let a_array: S<[u8; 0]> = S([]);
let b_array: S<[u16; 0]> = S([]); // This must not be merged with `a_array`.
let a_tuple: S<()> = S(());
let b_tuple: S<()> = S(()); // But this can be with `a_tuple`.
}
fn main() {
subexpression_elimination(2, 4, 5);
wrap_unwrap(5);
@ -243,6 +251,7 @@ fn main() {
references(5);
dereferences(&mut 5, &6, &S(7));
slices();
aggregates();
}
#[inline(never)]
@ -259,3 +268,4 @@ fn opaque(_: impl Sized) {}
// EMIT_MIR gvn.references.GVN.diff
// EMIT_MIR gvn.dereferences.GVN.diff
// EMIT_MIR gvn.slices.GVN.diff
// EMIT_MIR gvn.aggregates.GVN.diff