about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src/gvn.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_transform/src/gvn.rs')
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs56
1 files changed, 55 insertions, 1 deletions
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 283ed94b615..ca70dc36da0 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1368,7 +1368,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         let mut was_updated = false;
 
-        // If that cast just casts away the metadata again,
+        // Transmuting `*const T` <=> `*mut T` is just a pointer cast,
+        // which we might be able to merge with other ones later.
+        if let Transmute = kind
+            && let ty::RawPtr(from_pointee, _) = from.kind()
+            && let ty::RawPtr(to_pointee, _) = to.kind()
+            && from_pointee == to_pointee
+        {
+            *kind = PtrToPtr;
+            was_updated = true;
+        }
+
+        // If a cast just casts away the metadata again, then we can get it by
+        // casting the original thin pointer passed to `from_raw_parts`
         if let PtrToPtr = kind
             && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
                 self.get(value)
@@ -1397,6 +1409,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         }
 
+        // Aggregate-then-Transmute can just transmute the original field value,
+        // so long as the type is transparent over only that one single field.
+        if let Transmute = kind
+            && let Value::Aggregate(
+                AggregateTy::Def(aggregate_did, aggregate_args),
+                FIRST_VARIANT,
+                field_values,
+            ) = self.get(value)
+            && let [single_field_value] = **field_values
+            && let adt = self.tcx.adt_def(aggregate_did)
+            && adt.is_struct()
+            && adt.repr().transparent()
+        {
+            let field_ty = adt.non_enum_variant().single_field().ty(self.tcx, aggregate_args);
+            from = field_ty;
+            value = single_field_value;
+            was_updated = true;
+            if field_ty == to {
+                return Some(single_field_value);
+            }
+        }
+
         // PtrToPtr-then-Transmute can just transmute the original, so long as the
         // PtrToPtr didn't change metadata (and thus the size of the pointer)
         if let Transmute = kind
@@ -1416,6 +1450,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         }
 
+        // PtrToPtr-then-Transmute can just transmute the original, so long as the
+        // PtrToPtr didn't change metadata (and thus the size of the pointer)
+        if let PtrToPtr = kind
+            && let Value::Cast {
+                kind: Transmute,
+                value: inner_value,
+                from: inner_from,
+                to: _inner_to,
+            } = *self.get(value)
+            && self.pointers_have_same_metadata(from, to)
+        {
+            *kind = Transmute;
+            from = inner_from;
+            value = inner_value;
+            was_updated = true;
+            if inner_from == to {
+                return Some(inner_value);
+            }
+        }
+
         if was_updated && let Some(op) = self.try_as_operand(value, location) {
             *operand = op;
         }