From b4bbd3a48022f1d25da759b5d0408132159434b6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 12 May 2024 00:22:42 -0700 Subject: [PATCH] Enable GVN for `AggregateKind::RawPtr` --- compiler/rustc_mir_transform/src/gvn.rs | 19 ++++++-- tests/mir-opt/gvn.rs | 12 +++++ .../gvn.slice_index.GVN.panic-abort.diff | 48 +++++++++++++++++++ .../gvn.slice_index.GVN.panic-unwind.diff | 48 +++++++++++++++++++ 4 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 tests/mir-opt/gvn.slice_index.GVN.panic-abort.diff create mode 100644 tests/mir-opt/gvn.slice_index.GVN.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 342d1a1cd5bb0..feccd1fc56274 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -176,6 +176,9 @@ enum AggregateTy<'tcx> { Array, Tuple, Def(DefId, ty::GenericArgsRef<'tcx>), + /// Starting from `*const ()` and `usize` can give you any slice type, + /// so we just record the full type of the pointer here. + RawPtr { pointer_ty: Ty<'tcx> }, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -385,6 +388,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateTy::Def(def_id, args) => { self.tcx.type_of(def_id).instantiate(self.tcx, args) } + AggregateTy::RawPtr { pointer_ty } => pointer_ty, }; let variant = if ty.is_enum() { Some(variant) } else { None }; let ty = self.ecx.layout_of(ty).ok()?; @@ -399,7 +403,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; for (field_index, op) in fields.into_iter().enumerate() { let field_dest = self.ecx.project_field(&variant_dest, field_index).ok()?; - self.ecx.copy_op(op, &field_dest).ok()?; + if let AggregateTy::RawPtr { .. } = kind && field_index == 0 { + // The pointer field might be any thin pointer type, + // so avoid ICEing for a type mismatch. + self.ecx.copy_op_allow_transmute(op, &field_dest).ok()?; + } else { + self.ecx.copy_op(op, &field_dest).ok()?; + } } self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?; self.ecx @@ -927,8 +937,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Do not track unions. AggregateKind::Adt(_, _, _, _, Some(_)) => return None, - // FIXME: Do the extra work to GVN `from_raw_parts` - AggregateKind::RawPtr(..) => return None, + AggregateKind::RawPtr(pointee_ty, mtbl) => { + assert_eq!(fields.len(), 2); + let pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl); + (AggregateTy::RawPtr { pointer_ty }, FIRST_VARIANT) + } }; let fields: Option> = fields diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 9be3051528356..69e4b84bb1f29 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -781,6 +781,16 @@ fn non_freeze(x: T) { ) } +// Check that we can const-prop into `from_raw_parts` +fn slice_index(x: &[i32]) -> *const [i32] { + // CHECK-LABEL: fn slice_index( + // CHECK: _0 = *const [i32] from + // CHECK-SAME: const 123_usize); + let ptr = x.as_ptr(); + let len = 123; + std::intrinsics::aggregate_raw_ptr(ptr, len) +} + fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); @@ -805,6 +815,7 @@ fn main() { wide_ptr_integer(); borrowed(5); non_freeze(5); + slice_index(&[1]); } #[inline(never)] @@ -838,3 +849,4 @@ fn identity(x: T) -> T { // EMIT_MIR gvn.wide_ptr_integer.GVN.diff // EMIT_MIR gvn.borrowed.GVN.diff // EMIT_MIR gvn.non_freeze.GVN.diff +// EMIT_MIR gvn.slice_index.GVN.diff diff --git a/tests/mir-opt/gvn.slice_index.GVN.panic-abort.diff b/tests/mir-opt/gvn.slice_index.GVN.panic-abort.diff new file mode 100644 index 0000000000000..4349b8e937f33 --- /dev/null +++ b/tests/mir-opt/gvn.slice_index.GVN.panic-abort.diff @@ -0,0 +1,48 @@ +- // MIR for `slice_index` before GVN ++ // MIR for `slice_index` after GVN + + fn slice_index(_1: &[i32]) -> *const [i32] { + debug x => _1; + let mut _0: *const [i32]; + let _2: *const i32; + let mut _3: &[i32]; + let mut _5: *const i32; + let mut _6: usize; + scope 1 { + debug ptr => _2; + let _4: usize; + scope 2 { + debug len => _4; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = &(*_1); + _2 = core::slice::::as_ptr(move _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); +- StorageLive(_4); ++ nop; + _4 = const 123_usize; + StorageLive(_5); + _5 = _2; + StorageLive(_6); +- _6 = _4; +- _0 = *const [i32] from (move _5, move _6); ++ _6 = const 123_usize; ++ _0 = *const [i32] from (_2, const 123_usize); + StorageDead(_6); + StorageDead(_5); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.slice_index.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slice_index.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..1aa67f2064b28 --- /dev/null +++ b/tests/mir-opt/gvn.slice_index.GVN.panic-unwind.diff @@ -0,0 +1,48 @@ +- // MIR for `slice_index` before GVN ++ // MIR for `slice_index` after GVN + + fn slice_index(_1: &[i32]) -> *const [i32] { + debug x => _1; + let mut _0: *const [i32]; + let _2: *const i32; + let mut _3: &[i32]; + let mut _5: *const i32; + let mut _6: usize; + scope 1 { + debug ptr => _2; + let _4: usize; + scope 2 { + debug len => _4; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = &(*_1); + _2 = core::slice::::as_ptr(move _3) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_3); +- StorageLive(_4); ++ nop; + _4 = const 123_usize; + StorageLive(_5); + _5 = _2; + StorageLive(_6); +- _6 = _4; +- _0 = *const [i32] from (move _5, move _6); ++ _6 = const 123_usize; ++ _0 = *const [i32] from (_2, const 123_usize); + StorageDead(_6); + StorageDead(_5); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } +