Skip to content

Commit 1881281

Browse files
committed
Enable GVN for AggregateKind::RawPtr & UnOp::PtrMetadata
1 parent 23ea77b commit 1881281

8 files changed

+300
-5
lines changed

compiler/rustc_mir_transform/src/gvn.rs

+36-5
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@
8383
//! that contain `AllocId`s.
8484
8585
use rustc_const_eval::const_eval::DummyMachine;
86-
use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemoryKind};
87-
use rustc_const_eval::interpret::{ImmTy, InterpCx, OpTy, Projectable, Scalar};
86+
use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemPlaceMeta, MemoryKind};
87+
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable, Scalar};
8888
use rustc_data_structures::fx::FxIndexSet;
8989
use rustc_data_structures::graph::dominators::Dominators;
9090
use rustc_hir::def::DefKind;
@@ -99,7 +99,7 @@ use rustc_middle::ty::layout::LayoutOf;
9999
use rustc_middle::ty::{self, Ty, TyCtxt};
100100
use rustc_span::def_id::DefId;
101101
use rustc_span::DUMMY_SP;
102-
use rustc_target::abi::{self, Abi, Size, VariantIdx, FIRST_VARIANT};
102+
use rustc_target::abi::{self, Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
103103
use smallvec::SmallVec;
104104
use std::borrow::Cow;
105105

@@ -177,6 +177,11 @@ enum AggregateTy<'tcx> {
177177
Array,
178178
Tuple,
179179
Def(DefId, ty::GenericArgsRef<'tcx>),
180+
/// Neither of these types can be recovered from the other
181+
RawPtr {
182+
input_thin_pointer_ty: Ty<'tcx>,
183+
output_pointer_ty: Ty<'tcx>,
184+
},
180185
}
181186

182187
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -386,11 +391,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
386391
AggregateTy::Def(def_id, args) => {
387392
self.tcx.type_of(def_id).instantiate(self.tcx, args)
388393
}
394+
AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty,
389395
};
390396
let variant = if ty.is_enum() { Some(variant) } else { None };
391397
let ty = self.ecx.layout_of(ty).ok()?;
392398
if ty.is_zst() {
393399
ImmTy::uninit(ty).into()
400+
} else if matches!(kind, AggregateTy::RawPtr { .. }) {
401+
// Pointers don't have fields, so don't `project_field` them.
402+
let data = self.ecx.read_pointer(fields[0]).ok()?;
403+
let meta = if fields[1].layout.is_zst() {
404+
MemPlaceMeta::None
405+
} else {
406+
MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).ok()?)
407+
};
408+
let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx);
409+
ImmTy::from_immediate(ptr_imm, ty).into()
394410
} else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
395411
let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?;
396412
let variant_dest = if let Some(variant) = variant {
@@ -920,8 +936,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
920936
}
921937
// Do not track unions.
922938
AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
923-
// FIXME: Do the extra work to GVN `from_raw_parts`
924-
AggregateKind::RawPtr(..) => return None,
939+
AggregateKind::RawPtr(pointee_ty, mtbl) => {
940+
assert_eq!(fields.len(), 2);
941+
let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl);
942+
let input_thin_pointer_ty = fields[FieldIdx::ZERO].ty(self.local_decls, self.tcx);
943+
(AggregateTy::RawPtr { input_thin_pointer_ty, output_pointer_ty }, FIRST_VARIANT)
944+
}
925945
};
926946

927947
let fields: Option<Vec<_>> = fields
@@ -960,6 +980,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
960980
(UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => {
961981
Value::BinaryOp(BinOp::Eq, *lhs, *rhs)
962982
}
983+
(UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => {
984+
return Some(fields[1]);
985+
}
963986
_ => return None,
964987
};
965988

@@ -1082,6 +1105,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
10821105
return self.new_opaque();
10831106
}
10841107

1108+
if let PtrToPtr = kind
1109+
&& let Value::Aggregate(AggregateTy::RawPtr { input_thin_pointer_ty, .. }, _, fields) =
1110+
self.get(value)
1111+
&& to == *input_thin_pointer_ty
1112+
{
1113+
return Some(fields[0]);
1114+
}
1115+
10851116
if let PtrToPtr | PointerCoercion(MutToConstPointer) = kind
10861117
&& let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } =
10871118
*self.get(value)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
- // MIR for `meta_of_ref_to_slice` before GVN
2+
+ // MIR for `meta_of_ref_to_slice` after GVN
3+
4+
fn meta_of_ref_to_slice(_1: *const i32) -> usize {
5+
debug x => _1;
6+
let mut _0: usize;
7+
let _2: *const [i32];
8+
let mut _3: *const i32;
9+
let mut _4: *const [i32];
10+
scope 1 {
11+
debug ptr => _2;
12+
}
13+
14+
bb0: {
15+
- StorageLive(_2);
16+
+ nop;
17+
StorageLive(_3);
18+
_3 = _1;
19+
- _2 = *const [i32] from (move _3, const 1_usize);
20+
+ _2 = *const [i32] from (_1, const 1_usize);
21+
StorageDead(_3);
22+
StorageLive(_4);
23+
_4 = _2;
24+
- _0 = PtrMetadata(move _4);
25+
+ _0 = const 1_usize;
26+
StorageDead(_4);
27+
- StorageDead(_2);
28+
+ nop;
29+
return;
30+
}
31+
}
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
- // MIR for `meta_of_ref_to_slice` before GVN
2+
+ // MIR for `meta_of_ref_to_slice` after GVN
3+
4+
fn meta_of_ref_to_slice(_1: *const i32) -> usize {
5+
debug x => _1;
6+
let mut _0: usize;
7+
let _2: *const [i32];
8+
let mut _3: *const i32;
9+
let mut _4: *const [i32];
10+
scope 1 {
11+
debug ptr => _2;
12+
}
13+
14+
bb0: {
15+
- StorageLive(_2);
16+
+ nop;
17+
StorageLive(_3);
18+
_3 = _1;
19+
- _2 = *const [i32] from (move _3, const 1_usize);
20+
+ _2 = *const [i32] from (_1, const 1_usize);
21+
StorageDead(_3);
22+
StorageLive(_4);
23+
_4 = _2;
24+
- _0 = PtrMetadata(move _4);
25+
+ _0 = const 1_usize;
26+
StorageDead(_4);
27+
- StorageDead(_2);
28+
+ nop;
29+
return;
30+
}
31+
}
32+

tests/mir-opt/gvn.rs

+30
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,30 @@ fn non_freeze<T: Copy>(x: T) {
781781
)
782782
}
783783

784+
// Check that we can const-prop into `from_raw_parts`
785+
fn slice_const_length(x: &[i32]) -> *const [i32] {
786+
// CHECK-LABEL: fn slice_const_length(
787+
// CHECK: _0 = *const [i32] from
788+
// CHECK-SAME: const 123_usize);
789+
let ptr = x.as_ptr();
790+
let len = 123;
791+
std::intrinsics::aggregate_raw_ptr(ptr, len)
792+
}
793+
794+
fn meta_of_ref_to_slice(x: *const i32) -> usize {
795+
// CHECK-LABEL: fn meta_of_ref_to_slice
796+
// CHECK: _0 = const 1_usize
797+
let ptr: *const [i32] = std::intrinsics::aggregate_raw_ptr(x, 1);
798+
std::intrinsics::ptr_metadata(ptr)
799+
}
800+
801+
fn slice_from_raw_parts_as_ptr(x: *const u16, n: usize) -> *const u16 {
802+
// CHECK-LABEL: fn slice_from_raw_parts_as_ptr
803+
// CHECK: _0 = _1
804+
let ptr: *const [u16] = std::intrinsics::aggregate_raw_ptr(x, n);
805+
ptr as *const u16
806+
}
807+
784808
fn main() {
785809
subexpression_elimination(2, 4, 5);
786810
wrap_unwrap(5);
@@ -805,6 +829,9 @@ fn main() {
805829
wide_ptr_integer();
806830
borrowed(5);
807831
non_freeze(5);
832+
slice_const_length(&[1]);
833+
meta_of_ref_to_slice(&42);
834+
slice_from_raw_parts_as_ptr(&123, 456);
808835
}
809836

810837
#[inline(never)]
@@ -838,3 +865,6 @@ fn identity<T>(x: T) -> T {
838865
// EMIT_MIR gvn.wide_ptr_integer.GVN.diff
839866
// EMIT_MIR gvn.borrowed.GVN.diff
840867
// EMIT_MIR gvn.non_freeze.GVN.diff
868+
// EMIT_MIR gvn.slice_const_length.GVN.diff
869+
// EMIT_MIR gvn.meta_of_ref_to_slice.GVN.diff
870+
// EMIT_MIR gvn.slice_from_raw_parts_as_ptr.GVN.diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
- // MIR for `slice_const_length` before GVN
2+
+ // MIR for `slice_const_length` after GVN
3+
4+
fn slice_const_length(_1: &[i32]) -> *const [i32] {
5+
debug x => _1;
6+
let mut _0: *const [i32];
7+
let _2: *const i32;
8+
let mut _3: &[i32];
9+
let mut _5: *const i32;
10+
let mut _6: usize;
11+
scope 1 {
12+
debug ptr => _2;
13+
let _4: usize;
14+
scope 2 {
15+
debug len => _4;
16+
}
17+
}
18+
19+
bb0: {
20+
- StorageLive(_2);
21+
+ nop;
22+
StorageLive(_3);
23+
_3 = &(*_1);
24+
_2 = core::slice::<impl [i32]>::as_ptr(move _3) -> [return: bb1, unwind unreachable];
25+
}
26+
27+
bb1: {
28+
StorageDead(_3);
29+
- StorageLive(_4);
30+
+ nop;
31+
_4 = const 123_usize;
32+
StorageLive(_5);
33+
_5 = _2;
34+
StorageLive(_6);
35+
- _6 = _4;
36+
- _0 = *const [i32] from (move _5, move _6);
37+
+ _6 = const 123_usize;
38+
+ _0 = *const [i32] from (_2, const 123_usize);
39+
StorageDead(_6);
40+
StorageDead(_5);
41+
- StorageDead(_4);
42+
- StorageDead(_2);
43+
+ nop;
44+
+ nop;
45+
return;
46+
}
47+
}
48+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
- // MIR for `slice_const_length` before GVN
2+
+ // MIR for `slice_const_length` after GVN
3+
4+
fn slice_const_length(_1: &[i32]) -> *const [i32] {
5+
debug x => _1;
6+
let mut _0: *const [i32];
7+
let _2: *const i32;
8+
let mut _3: &[i32];
9+
let mut _5: *const i32;
10+
let mut _6: usize;
11+
scope 1 {
12+
debug ptr => _2;
13+
let _4: usize;
14+
scope 2 {
15+
debug len => _4;
16+
}
17+
}
18+
19+
bb0: {
20+
- StorageLive(_2);
21+
+ nop;
22+
StorageLive(_3);
23+
_3 = &(*_1);
24+
_2 = core::slice::<impl [i32]>::as_ptr(move _3) -> [return: bb1, unwind continue];
25+
}
26+
27+
bb1: {
28+
StorageDead(_3);
29+
- StorageLive(_4);
30+
+ nop;
31+
_4 = const 123_usize;
32+
StorageLive(_5);
33+
_5 = _2;
34+
StorageLive(_6);
35+
- _6 = _4;
36+
- _0 = *const [i32] from (move _5, move _6);
37+
+ _6 = const 123_usize;
38+
+ _0 = *const [i32] from (_2, const 123_usize);
39+
StorageDead(_6);
40+
StorageDead(_5);
41+
- StorageDead(_4);
42+
- StorageDead(_2);
43+
+ nop;
44+
+ nop;
45+
return;
46+
}
47+
}
48+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
- // MIR for `slice_from_raw_parts_as_ptr` before GVN
2+
+ // MIR for `slice_from_raw_parts_as_ptr` after GVN
3+
4+
fn slice_from_raw_parts_as_ptr(_1: *const u16, _2: usize) -> *const u16 {
5+
debug x => _1;
6+
debug n => _2;
7+
let mut _0: *const u16;
8+
let _3: *const [u16];
9+
let mut _4: *const u16;
10+
let mut _5: usize;
11+
let mut _6: *const [u16];
12+
scope 1 {
13+
debug ptr => _3;
14+
}
15+
16+
bb0: {
17+
- StorageLive(_3);
18+
+ nop;
19+
StorageLive(_4);
20+
_4 = _1;
21+
StorageLive(_5);
22+
_5 = _2;
23+
- _3 = *const [u16] from (move _4, move _5);
24+
+ _3 = *const [u16] from (_1, _2);
25+
StorageDead(_5);
26+
StorageDead(_4);
27+
StorageLive(_6);
28+
_6 = _3;
29+
- _0 = move _6 as *const u16 (PtrToPtr);
30+
+ _0 = _1;
31+
StorageDead(_6);
32+
- StorageDead(_3);
33+
+ nop;
34+
return;
35+
}
36+
}
37+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
- // MIR for `slice_from_raw_parts_as_ptr` before GVN
2+
+ // MIR for `slice_from_raw_parts_as_ptr` after GVN
3+
4+
fn slice_from_raw_parts_as_ptr(_1: *const u16, _2: usize) -> *const u16 {
5+
debug x => _1;
6+
debug n => _2;
7+
let mut _0: *const u16;
8+
let _3: *const [u16];
9+
let mut _4: *const u16;
10+
let mut _5: usize;
11+
let mut _6: *const [u16];
12+
scope 1 {
13+
debug ptr => _3;
14+
}
15+
16+
bb0: {
17+
- StorageLive(_3);
18+
+ nop;
19+
StorageLive(_4);
20+
_4 = _1;
21+
StorageLive(_5);
22+
_5 = _2;
23+
- _3 = *const [u16] from (move _4, move _5);
24+
+ _3 = *const [u16] from (_1, _2);
25+
StorageDead(_5);
26+
StorageDead(_4);
27+
StorageLive(_6);
28+
_6 = _3;
29+
- _0 = move _6 as *const u16 (PtrToPtr);
30+
+ _0 = _1;
31+
StorageDead(_6);
32+
- StorageDead(_3);
33+
+ nop;
34+
return;
35+
}
36+
}
37+

0 commit comments

Comments
 (0)