diff options
| author | Scott McMurray <scottmcm@users.noreply.github.com> | 2024-11-21 17:59:43 -0800 |
|---|---|---|
| committer | Scott McMurray <scottmcm@users.noreply.github.com> | 2025-01-08 18:46:30 -0800 |
| commit | 8dcc676c9283b040d1ef6d66f156ff2212544b10 (patch) | |
| tree | 845110d0bc935ff32d70963c479d3f0f60925ff0 /compiler/rustc_mir_transform/src | |
| parent | e26ff2f9086fc449b963df578f8641c31846abe6 (diff) | |
| download | rust-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.rs | 56 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/instsimplify.rs | 23 |
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; - } - } - } } } } |
