about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2023-05-21 12:59:38 +0000
committerCamille GILLOT <gillot.camille@gmail.com>2023-10-25 06:46:47 +0000
commit80a5e8522de648d70a9ef1dfba7621f730832fb3 (patch)
treec4d05921cef957fd40b7b502e3ea2f919b7dbb25
parent23d4857080a3968447adbb1d55b2720dba46d666 (diff)
downloadrust-80a5e8522de648d70a9ef1dfba7621f730832fb3.tar.gz
rust-80a5e8522de648d70a9ef1dfba7621f730832fb3.zip
Extract simplify_aggregate.
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs83
-rw-r--r--tests/mir-opt/gvn.aggregates.GVN.panic-abort.diff66
-rw-r--r--tests/mir-opt/gvn.aggregates.GVN.panic-unwind.diff66
-rw-r--r--tests/mir-opt/gvn.rs10
4 files changed, 198 insertions, 27 deletions
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<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>(
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