about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2024-11-21 17:59:43 -0800
committerScott McMurray <scottmcm@users.noreply.github.com>2025-01-08 18:46:30 -0800
commit8dcc676c9283b040d1ef6d66f156ff2212544b10 (patch)
tree845110d0bc935ff32d70963c479d3f0f60925ff0 /compiler/rustc_mir_transform/src
parente26ff2f9086fc449b963df578f8641c31846abe6 (diff)
downloadrust-8dcc676c9283b040d1ef6d66f156ff2212544b10.tar.gz
rust-8dcc676c9283b040d1ef6d66f156ff2212544b10.zip
[mir-opt] GVN some more transmute cases
We already did `Transmute`-then-`PtrToPtr`; this adds the nearly-identical `PtrToPtr`-then-`Transmute`.

It also adds `transmute(Foo(x))` → `transmute(x)`, when `Foo` is a single-field transparent type.  That's useful for things like `NonNull { pointer: p }.as_ptr()`.

Found these as I was looking at MCP807-related changes.
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs56
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs23
2 files changed, 55 insertions, 24 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;
         }
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 1a65affe812..9e024508c58 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -173,29 +173,6 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
                     *kind = CastKind::IntToInt;
                     return;
                 }
-
-                // Transmuting a transparent struct/union to a field's type is a projection
-                if let ty::Adt(adt_def, args) = operand_ty.kind()
-                    && adt_def.repr().transparent()
-                    && (adt_def.is_struct() || adt_def.is_union())
-                    && let Some(place) = operand.place()
-                {
-                    let variant = adt_def.non_enum_variant();
-                    for (i, field) in variant.fields.iter_enumerated() {
-                        let field_ty = field.ty(self.tcx, args);
-                        if field_ty == *cast_ty {
-                            let place = place
-                                .project_deeper(&[ProjectionElem::Field(i, *cast_ty)], self.tcx);
-                            let operand = if operand.is_move() {
-                                Operand::Move(place)
-                            } else {
-                                Operand::Copy(place)
-                            };
-                            *rvalue = Rvalue::Use(operand);
-                            return;
-                        }
-                    }
-                }
             }
         }
     }