about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2023-09-16 09:35:46 +0000
committerCamille GILLOT <gillot.camille@gmail.com>2023-10-25 06:46:47 +0000
commit48d2157a89ffddce3287c57b3e3817a7e093b6c5 (patch)
tree1102b41765d669b7ca3ea6488ebfcca3406c8ef2 /compiler/rustc_mir_transform/src
parent692e5286479e16b3e9b47ab842b543985e1a6ceb (diff)
downloadrust-48d2157a89ffddce3287c57b3e3817a7e093b6c5.tar.gz
rust-48d2157a89ffddce3287c57b3e3817a7e093b6c5.zip
Simplify aggregate projections.
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs41
1 files changed, 40 insertions, 1 deletions
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index eaa1c70a5e9..70d0f22a7b9 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -276,6 +276,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         }
     }
 
+    fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex {
+        self.insert(Value::Constant(Const::from_scalar(self.tcx, scalar, ty)))
+    }
+
     #[instrument(level = "trace", skip(self), ret)]
     fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
         use Value::*;
@@ -483,12 +487,33 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 }
             }
             ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index),
-            ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty),
+            ProjectionElem::Field(f, ty) => {
+                if let Value::Aggregate(_, _, fields) = self.get(value) {
+                    return Some(fields[f.as_usize()]);
+                } else if let Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)) = self.get(value)
+                    && let Value::Aggregate(_, written_variant, fields) = self.get(*outer_value)
+                    && written_variant == read_variant
+                {
+                    return Some(fields[f.as_usize()]);
+                }
+                ProjectionElem::Field(f, ty)
+            }
             ProjectionElem::Index(idx) => {
                 let idx = self.locals[idx]?;
                 ProjectionElem::Index(idx)
             }
             ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+                match self.get(value) {
+                    Value::Aggregate(ty, _, operands) if ty.is_array() => {
+                        let offset = if from_end {
+                            operands.len() - offset as usize
+                        } else {
+                            offset as usize
+                        };
+                        return operands.get(offset).copied();
+                    }
+                    _ => {}
+                };
                 ProjectionElem::ConstantIndex { offset, min_length, from_end }
             }
             ProjectionElem::Subslice { from, to, from_end } => {
@@ -679,6 +704,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
             Rvalue::Discriminant(ref mut place) => {
                 let place = self.simplify_place_value(place, location)?;
+                if let Some(discr) = self.simplify_discriminant(place) {
+                    return Some(discr);
+                }
                 Value::Discriminant(place)
             }
 
@@ -688,6 +716,17 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         debug!(?value);
         Some(self.insert(value))
     }
+
+    fn simplify_discriminant(&mut self, place: VnIndex) -> Option<VnIndex> {
+        if let Value::Aggregate(enum_ty, variant, _) = *self.get(place)
+            && enum_ty.is_enum()
+        {
+            let discr = self.ecx.discriminant_for_variant(enum_ty, variant).ok()?;
+            return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty));
+        }
+
+        None
+    }
 }
 
 fn op_to_prop_const<'tcx>(