diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 9880e239957..bbcb39226b7 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -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> = 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> { + 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> = 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>( diff --git a/tests/mir-opt/gvn.aggregates.GVN.panic-abort.diff b/tests/mir-opt/gvn.aggregates.GVN.panic-abort.diff new file mode 100644 index 00000000000..c442835bfa9 --- /dev/null +++ b/tests/mir-opt/gvn.aggregates.GVN.panic-abort.diff @@ -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; + } + } + diff --git a/tests/mir-opt/gvn.aggregates.GVN.panic-unwind.diff b/tests/mir-opt/gvn.aggregates.GVN.panic-unwind.diff new file mode 100644 index 00000000000..c442835bfa9 --- /dev/null +++ b/tests/mir-opt/gvn.aggregates.GVN.panic-unwind.diff @@ -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; + } + } + diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 3633f9c23cd..ff176a6597b 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -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