Skip to content

Commit f000b42

Browse files
authored
Rollup merge of #125041 - scottmcm:gvn-for-from-raw-parts, r=cjgillot
Enable GVN for `AggregateKind::RawPtr` Looks like I was worried for nothing; this seems like it's much easier than I was originally thinking it would be. r? `@cjgillot` This should be useful for `x[..4]`-like things, should those start inlining enough to expose the lengths.
2 parents 7bb0ef4 + 021ccf6 commit f000b42

14 files changed

+519
-26
lines changed

compiler/rustc_mir_transform/src/gvn.rs

+87-12
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::{HasParamEnv, 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,12 @@ enum AggregateTy<'tcx> {
177177
Array,
178178
Tuple,
179179
Def(DefId, ty::GenericArgsRef<'tcx>),
180+
RawPtr {
181+
/// Needed for cast propagation.
182+
data_pointer_ty: Ty<'tcx>,
183+
/// The data pointer can be anything thin, so doesn't determine the output.
184+
output_pointer_ty: Ty<'tcx>,
185+
},
180186
}
181187

182188
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -385,11 +391,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
385391
AggregateTy::Def(def_id, args) => {
386392
self.tcx.type_of(def_id).instantiate(self.tcx, args)
387393
}
394+
AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty,
388395
};
389396
let variant = if ty.is_enum() { Some(variant) } else { None };
390397
let ty = self.ecx.layout_of(ty).ok()?;
391398
if ty.is_zst() {
392399
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()
393410
} else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
394411
let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?;
395412
let variant_dest = if let Some(variant) = variant {
@@ -864,10 +881,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
864881
rvalue: &mut Rvalue<'tcx>,
865882
location: Location,
866883
) -> Option<VnIndex> {
867-
let Rvalue::Aggregate(box ref kind, ref mut fields) = *rvalue else { bug!() };
884+
let Rvalue::Aggregate(box ref kind, ref mut field_ops) = *rvalue else { bug!() };
868885

869886
let tcx = self.tcx;
870-
if fields.is_empty() {
887+
if field_ops.is_empty() {
871888
let is_zst = match *kind {
872889
AggregateKind::Array(..)
873890
| AggregateKind::Tuple
@@ -886,13 +903,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
886903
}
887904
}
888905

889-
let (ty, variant_index) = match *kind {
906+
let (mut ty, variant_index) = match *kind {
890907
AggregateKind::Array(..) => {
891-
assert!(!fields.is_empty());
908+
assert!(!field_ops.is_empty());
892909
(AggregateTy::Array, FIRST_VARIANT)
893910
}
894911
AggregateKind::Tuple => {
895-
assert!(!fields.is_empty());
912+
assert!(!field_ops.is_empty());
896913
(AggregateTy::Tuple, FIRST_VARIANT)
897914
}
898915
AggregateKind::Closure(did, args)
@@ -903,15 +920,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
903920
}
904921
// Do not track unions.
905922
AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
906-
// FIXME: Do the extra work to GVN `from_raw_parts`
907-
AggregateKind::RawPtr(..) => return None,
923+
AggregateKind::RawPtr(pointee_ty, mtbl) => {
924+
assert_eq!(field_ops.len(), 2);
925+
let data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx);
926+
let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl);
927+
(AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty }, FIRST_VARIANT)
928+
}
908929
};
909930

910-
let fields: Option<Vec<_>> = fields
931+
let fields: Option<Vec<_>> = field_ops
911932
.iter_mut()
912933
.map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque()))
913934
.collect();
914-
let fields = fields?;
935+
let mut fields = fields?;
936+
937+
if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty {
938+
let mut was_updated = false;
939+
940+
// Any thin pointer of matching mutability is fine as the data pointer.
941+
while let Value::Cast {
942+
kind: CastKind::PtrToPtr,
943+
value: cast_value,
944+
from: cast_from,
945+
to: _,
946+
} = self.get(fields[0])
947+
&& let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind()
948+
&& let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind()
949+
&& from_mtbl == output_mtbl
950+
&& from_pointee_ty.is_sized(self.tcx, self.param_env)
951+
{
952+
fields[0] = *cast_value;
953+
*data_pointer_ty = *cast_from;
954+
was_updated = true;
955+
}
956+
957+
if was_updated {
958+
if let Some(const_) = self.try_as_constant(fields[0]) {
959+
field_ops[FieldIdx::ZERO] = Operand::Constant(Box::new(const_));
960+
} else if let Some(local) = self.try_as_local(fields[0], location) {
961+
field_ops[FieldIdx::ZERO] = Operand::Copy(Place::from(local));
962+
self.reused_locals.insert(local);
963+
}
964+
}
965+
}
915966

916967
if let AggregateTy::Array = ty
917968
&& fields.len() > 4
@@ -943,6 +994,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
943994
(UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => {
944995
Value::BinaryOp(BinOp::Eq, *lhs, *rhs)
945996
}
997+
(UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => {
998+
return Some(fields[1]);
999+
}
9461000
_ => return None,
9471001
};
9481002

@@ -1094,6 +1148,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
10941148
return self.new_opaque();
10951149
}
10961150

1151+
let mut was_updated = false;
1152+
1153+
// If that cast just casts away the metadata again,
1154+
if let PtrToPtr = kind
1155+
&& let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
1156+
self.get(value)
1157+
&& let ty::RawPtr(to_pointee, _) = to.kind()
1158+
&& to_pointee.is_sized(self.tcx, self.param_env)
1159+
{
1160+
from = *data_pointer_ty;
1161+
value = fields[0];
1162+
was_updated = true;
1163+
if *data_pointer_ty == to {
1164+
return Some(fields[0]);
1165+
}
1166+
}
1167+
10971168
if let PtrToPtr | PointerCoercion(MutToConstPointer) = kind
10981169
&& let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } =
10991170
*self.get(value)
@@ -1102,9 +1173,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
11021173
from = inner_from;
11031174
value = inner_value;
11041175
*kind = PtrToPtr;
1176+
was_updated = true;
11051177
if inner_from == to {
11061178
return Some(inner_value);
11071179
}
1180+
}
1181+
1182+
if was_updated {
11081183
if let Some(const_) = self.try_as_constant(value) {
11091184
*operand = Operand::Constant(Box::new(const_));
11101185
} else if let Some(local) = self.try_as_local(value, location) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
- // MIR for `casts_before_aggregate_raw_ptr` before GVN
2+
+ // MIR for `casts_before_aggregate_raw_ptr` after GVN
3+
4+
fn casts_before_aggregate_raw_ptr(_1: *const u32) -> *const [u8] {
5+
debug x => _1;
6+
let mut _0: *const [u8];
7+
let _2: *const [u8; 4];
8+
let mut _3: *const u32;
9+
let mut _5: *const [u8; 4];
10+
let mut _7: *const u8;
11+
let mut _8: *const ();
12+
scope 1 {
13+
debug x => _2;
14+
let _4: *const u8;
15+
scope 2 {
16+
debug x => _4;
17+
let _6: *const ();
18+
scope 3 {
19+
debug x => _6;
20+
}
21+
}
22+
}
23+
24+
bb0: {
25+
- StorageLive(_2);
26+
+ nop;
27+
StorageLive(_3);
28+
_3 = _1;
29+
- _2 = move _3 as *const [u8; 4] (PtrToPtr);
30+
+ _2 = _1 as *const [u8; 4] (PtrToPtr);
31+
StorageDead(_3);
32+
- StorageLive(_4);
33+
+ nop;
34+
StorageLive(_5);
35+
_5 = _2;
36+
- _4 = move _5 as *const u8 (PtrToPtr);
37+
+ _4 = _1 as *const u8 (PtrToPtr);
38+
StorageDead(_5);
39+
- StorageLive(_6);
40+
+ nop;
41+
StorageLive(_7);
42+
_7 = _4;
43+
- _6 = move _7 as *const () (PtrToPtr);
44+
+ _6 = _1 as *const () (PtrToPtr);
45+
StorageDead(_7);
46+
StorageLive(_8);
47+
_8 = _6;
48+
- _0 = *const [u8] from (move _8, const 4_usize);
49+
+ _0 = *const [u8] from (_1, const 4_usize);
50+
StorageDead(_8);
51+
- StorageDead(_6);
52+
- StorageDead(_4);
53+
- StorageDead(_2);
54+
+ nop;
55+
+ nop;
56+
+ nop;
57+
return;
58+
}
59+
}
60+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
- // MIR for `casts_before_aggregate_raw_ptr` before GVN
2+
+ // MIR for `casts_before_aggregate_raw_ptr` after GVN
3+
4+
fn casts_before_aggregate_raw_ptr(_1: *const u32) -> *const [u8] {
5+
debug x => _1;
6+
let mut _0: *const [u8];
7+
let _2: *const [u8; 4];
8+
let mut _3: *const u32;
9+
let mut _5: *const [u8; 4];
10+
let mut _7: *const u8;
11+
let mut _8: *const ();
12+
scope 1 {
13+
debug x => _2;
14+
let _4: *const u8;
15+
scope 2 {
16+
debug x => _4;
17+
let _6: *const ();
18+
scope 3 {
19+
debug x => _6;
20+
}
21+
}
22+
}
23+
24+
bb0: {
25+
- StorageLive(_2);
26+
+ nop;
27+
StorageLive(_3);
28+
_3 = _1;
29+
- _2 = move _3 as *const [u8; 4] (PtrToPtr);
30+
+ _2 = _1 as *const [u8; 4] (PtrToPtr);
31+
StorageDead(_3);
32+
- StorageLive(_4);
33+
+ nop;
34+
StorageLive(_5);
35+
_5 = _2;
36+
- _4 = move _5 as *const u8 (PtrToPtr);
37+
+ _4 = _1 as *const u8 (PtrToPtr);
38+
StorageDead(_5);
39+
- StorageLive(_6);
40+
+ nop;
41+
StorageLive(_7);
42+
_7 = _4;
43+
- _6 = move _7 as *const () (PtrToPtr);
44+
+ _6 = _1 as *const () (PtrToPtr);
45+
StorageDead(_7);
46+
StorageLive(_8);
47+
_8 = _6;
48+
- _0 = *const [u8] from (move _8, const 4_usize);
49+
+ _0 = *const [u8] from (_1, const 4_usize);
50+
StorageDead(_8);
51+
- StorageDead(_6);
52+
- StorageDead(_4);
53+
- StorageDead(_2);
54+
+ nop;
55+
+ nop;
56+
+ nop;
57+
return;
58+
}
59+
}
60+
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+

0 commit comments

Comments
 (0)