Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit bcb40db

Browse files
committed
Auto merge of rust-lang#126541 - scottmcm:more-ptr-metadata-gvn, r=<try>
More ptr metadata gvn There's basically 3 parts to this PR. 1. Allow references as arguments to `UnOp::PtrMetadata` This is a MIR semantics addition, so r? mir Rather than just raw pointers, also allow references to be passed to `PtrMetadata`. That means the length of a slice can be just `PtrMetadata(_1)` instead of also needing a ref-to-pointer statement (`_2 = &raw *_1` + `PtrMetadata(_2)`). AFAIK there should be no provenance or tagging implications of looking at the *metadata* of a pointer, and the code in the backends actually already supported it (other than a debug assert, given that they don't care about ptr vs reference, really), so we might as well allow it. 2. Simplify the argument to `PtrMetadata` in GVN Because the specific kind of pointer-like thing isn't that important, GVN can simplify all those details away. Things like `*const`-to-`*mut` casts and `&mut`-to-`&` reborrows are irrelevant, and skipping them lets it see more interesting things. cc `@cjgillot` Notably, unsizing casts for arrays. GVN supported that for `Len`, and now it sees it for `PtrMetadata` as well, allowing `PtrMetadata(pointer)` to become a constant if that pointer came from an array-to-slice unsizing, even through a bunch of other possible steps. 3. Replace `NormalizeArrayLen` with GVN The `NormalizeArrayLen` pass hasn't been running even in optimized builds for well over a year, and it turns out that GVN -- which *is* on in optimized builds -- can do everything it was trying to do. So the code for the pass is deleted, but the tests are kept, just changed to the different pass. As part of this, `LowerSliceLen` was changed to emit `PtrMetadata(_1)` instead of `Len(*_1)`, a small step on the road to eventually eliminating `Rvalue::Len`.
2 parents 12b33d3 + 72cda61 commit bcb40db

File tree

45 files changed

+453
-294
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+453
-294
lines changed

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
638638
(OperandValue::Immediate(llval), operand.layout)
639639
}
640640
mir::UnOp::PtrMetadata => {
641-
debug_assert!(operand.layout.ty.is_unsafe_ptr());
641+
debug_assert!(
642+
operand.layout.ty.is_unsafe_ptr() || operand.layout.ty.is_ref(),
643+
);
642644
let (_, meta) = operand.val.pointer_parts();
643645
assert_eq!(operand.layout.fields.count() > 1, meta.is_some());
644646
if let Some(meta) = meta {

compiler/rustc_const_eval/src/interpret/operator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
460460
let res = ScalarInt::truncate_from_uint(res, layout.size).0;
461461
Ok(ImmTy::from_scalar(res.into(), layout))
462462
}
463-
ty::RawPtr(..) => {
463+
ty::RawPtr(..) | ty::Ref(..) => {
464464
assert_eq!(un_op, PtrMetadata);
465465
let (_, meta) = val.to_scalar_and_meta();
466466
Ok(match meta {

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -840,8 +840,56 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
840840
}
841841
Value::BinaryOp(op, lhs, rhs)
842842
}
843-
Rvalue::UnaryOp(op, ref mut arg) => {
844-
let arg = self.simplify_operand(arg, location)?;
843+
Rvalue::UnaryOp(op, ref mut arg_op) => {
844+
let mut arg = self.simplify_operand(arg_op, location)?;
845+
846+
// PtrMetadata doesn't care about *const vs *mut vs & vs &mut,
847+
// so start by removing those distinctions so we can update the `Operand`
848+
if op == UnOp::PtrMetadata {
849+
let mut was_updated = false;
850+
loop {
851+
let value = self.get(arg);
852+
853+
// FIXME: remove MutToConst after #126308
854+
if let Value::Cast {
855+
kind:
856+
CastKind::PtrToPtr
857+
| CastKind::PointerCoercion(
858+
ty::adjustment::PointerCoercion::MutToConstPointer,
859+
),
860+
value: inner,
861+
from,
862+
to,
863+
} = value
864+
&& from.builtin_deref(true) == to.builtin_deref(true)
865+
{
866+
arg = *inner;
867+
was_updated = true;
868+
continue;
869+
}
870+
871+
if let Value::Address { place, kind: _, provenance: _ } = value
872+
&& let PlaceRef { local, projection: [PlaceElem::Deref] } =
873+
place.as_ref()
874+
&& let Some(local_index) = self.locals[local]
875+
{
876+
arg = local_index;
877+
was_updated = true;
878+
continue;
879+
}
880+
881+
if was_updated {
882+
if let Some(const_) = self.try_as_constant(arg) {
883+
*arg_op = Operand::Constant(Box::new(const_));
884+
} else if let Some(local) = self.try_as_local(arg, location) {
885+
*arg_op = Operand::Copy(Place::from(local));
886+
self.reused_locals.insert(local);
887+
}
888+
}
889+
break;
890+
}
891+
}
892+
845893
if let Some(value) = self.simplify_unary(op, arg) {
846894
return Some(value);
847895
}
@@ -996,6 +1044,24 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
9961044
(UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => {
9971045
return Some(fields[1]);
9981046
}
1047+
// We have an unsizing cast, which assigns the length to fat pointer metadata.
1048+
(
1049+
UnOp::PtrMetadata,
1050+
Value::Cast {
1051+
kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize),
1052+
from,
1053+
to,
1054+
..
1055+
},
1056+
) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind()
1057+
&& let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() =>
1058+
{
1059+
return self.insert_constant(Const::from_ty_const(
1060+
*len,
1061+
self.tcx.types.usize,
1062+
self.tcx,
1063+
));
1064+
}
9991065
_ => return None,
10001066
};
10011067

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ mod lower_slice_len;
8888
mod match_branches;
8989
mod mentioned_items;
9090
mod multiple_return_terminators;
91-
mod normalize_array_len;
9291
mod nrvo;
9392
mod prettify;
9493
mod promote_consts;
@@ -581,9 +580,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
581580
&o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching),
582581
// Inlining may have introduced a lot of redundant code and a large move pattern.
583582
// Now, we need to shrink the generated MIR.
584-
585-
// Has to run after `slice::len` lowering
586-
&normalize_array_len::NormalizeArrayLen,
587583
&ref_prop::ReferencePropagation,
588584
&sroa::ScalarReplacementOfAggregates,
589585
&match_branches::MatchBranchSimplification,

compiler/rustc_mir_transform/src/lower_slice_len.rs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
//! This pass lowers calls to core::slice::len to just Len op.
1+
//! This pass lowers calls to core::slice::len to just PtrMetadata op.
22
//! It should run before inlining!
33
44
use rustc_hir::def_id::DefId;
5-
use rustc_index::IndexSlice;
65
use rustc_middle::mir::*;
7-
use rustc_middle::ty::{self, TyCtxt};
6+
use rustc_middle::ty::TyCtxt;
87

98
pub struct LowerSliceLenCalls;
109

@@ -29,16 +28,11 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
2928
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
3029
for block in basic_blocks {
3130
// lower `<[_]>::len` calls
32-
lower_slice_len_call(tcx, block, &body.local_decls, slice_len_fn_item_def_id);
31+
lower_slice_len_call(block, slice_len_fn_item_def_id);
3332
}
3433
}
3534

36-
fn lower_slice_len_call<'tcx>(
37-
tcx: TyCtxt<'tcx>,
38-
block: &mut BasicBlockData<'tcx>,
39-
local_decls: &IndexSlice<Local, LocalDecl<'tcx>>,
40-
slice_len_fn_item_def_id: DefId,
41-
) {
35+
fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_item_def_id: DefId) {
4236
let terminator = block.terminator();
4337
if let TerminatorKind::Call {
4438
func,
@@ -50,19 +44,17 @@ fn lower_slice_len_call<'tcx>(
5044
} = &terminator.kind
5145
// some heuristics for fast rejection
5246
&& let [arg] = &args[..]
53-
&& let Some(arg) = arg.node.place()
54-
&& let ty::FnDef(fn_def_id, _) = func.ty(local_decls, tcx).kind()
55-
&& *fn_def_id == slice_len_fn_item_def_id
47+
&& let Some((fn_def_id, _)) = func.const_fn_def()
48+
&& fn_def_id == slice_len_fn_item_def_id
5649
{
5750
// perform modifications from something like:
5851
// _5 = core::slice::<impl [u8]>::len(move _6) -> bb1
5952
// into:
60-
// _5 = Len(*_6)
53+
// _5 = PtrMetadata(move _6)
6154
// goto bb1
6255

6356
// make new RValue for Len
64-
let deref_arg = tcx.mk_place_deref(arg);
65-
let r_value = Rvalue::Len(deref_arg);
57+
let r_value = Rvalue::UnaryOp(UnOp::PtrMetadata, arg.node.clone());
6658
let len_statement_kind = StatementKind::Assign(Box::new((*destination, r_value)));
6759
let add_statement =
6860
Statement { kind: len_statement_kind, source_info: terminator.source_info };

compiler/rustc_mir_transform/src/normalize_array_len.rs

Lines changed: 0 additions & 103 deletions
This file was deleted.

compiler/rustc_mir_transform/src/validate.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,12 +1116,17 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11161116
UnOp::PtrMetadata => {
11171117
if !matches!(self.mir_phase, MirPhase::Runtime(_)) {
11181118
// It would probably be fine to support this in earlier phases,
1119-
// but at the time of writing it's only ever introduced from intrinsic lowering,
1119+
// but at the time of writing it's only ever introduced from intrinsic lowering
1120+
// or other runtime-phase optimization passes,
11201121
// so earlier things can just `bug!` on it.
11211122
self.fail(location, "PtrMetadata should be in runtime MIR only");
11221123
}
11231124

1124-
check_kinds!(a, "Cannot PtrMetadata non-pointer type {:?}", ty::RawPtr(..));
1125+
check_kinds!(
1126+
a,
1127+
"Cannot PtrMetadata non-pointer non-reference type {:?}",
1128+
ty::RawPtr(..) | ty::Ref(..)
1129+
);
11251130
}
11261131
}
11271132
}

tests/coverage/closure_macro.cov-map

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,19 @@ Number of file 0 mappings: 5
2222
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
2323

2424
Function name: closure_macro::main::{closure#0}
25-
Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
25+
Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
2626
Number of files: 1
2727
- file 0 => global file 1
2828
Number of expressions: 3
2929
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
3030
- expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add)
31-
- expression 2 operands: lhs = Counter(2), rhs = Zero
31+
- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
3232
Number of file 0 mappings: 5
3333
- Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33)
3434
- Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39)
3535
- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22)
3636
= (c0 - c1)
37-
- Code(Zero) at (prev + 0, 23) to (start + 0, 30)
37+
- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30)
3838
- Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10)
39-
= (c1 + (c2 + Zero))
39+
= (c1 + (c2 + c3))
4040

tests/coverage/closure_macro_async.cov-map

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,19 @@ Number of file 0 mappings: 5
3030
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
3131

3232
Function name: closure_macro_async::test::{closure#0}::{closure#0}
33-
Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 12, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
33+
Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 12, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
3434
Number of files: 1
3535
- file 0 => global file 1
3636
Number of expressions: 3
3737
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
3838
- expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add)
39-
- expression 2 operands: lhs = Counter(2), rhs = Zero
39+
- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
4040
Number of file 0 mappings: 5
4141
- Code(Counter(0)) at (prev + 18, 28) to (start + 3, 33)
4242
- Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39)
4343
- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22)
4444
= (c0 - c1)
45-
- Code(Zero) at (prev + 0, 23) to (start + 0, 30)
45+
- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30)
4646
- Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10)
47-
= (c1 + (c2 + Zero))
47+
= (c1 + (c2 + c3))
4848

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
- // MIR for `array_len` before GVN
2+
+ // MIR for `array_len` after GVN
3+
4+
fn array_len(_1: &mut [i32; 42]) -> usize {
5+
debug x => _1;
6+
let mut _0: usize;
7+
let _2: *mut [i32];
8+
let mut _3: *mut [i32; 42];
9+
let mut _4: *const [i32];
10+
let mut _5: *mut [i32];
11+
scope 1 {
12+
debug x => _2;
13+
}
14+
15+
bb0: {
16+
- StorageLive(_2);
17+
+ nop;
18+
StorageLive(_3);
19+
_3 = &raw mut (*_1);
20+
_2 = move _3 as *mut [i32] (PointerCoercion(Unsize));
21+
StorageDead(_3);
22+
StorageLive(_4);
23+
StorageLive(_5);
24+
_5 = _2;
25+
- _4 = move _5 as *const [i32] (PointerCoercion(MutToConstPointer));
26+
+ _4 = _2 as *const [i32] (PointerCoercion(MutToConstPointer));
27+
StorageDead(_5);
28+
- _0 = PtrMetadata(move _4);
29+
+ _0 = const 42_usize;
30+
StorageDead(_4);
31+
- StorageDead(_2);
32+
+ nop;
33+
return;
34+
}
35+
}
36+

0 commit comments

Comments
 (0)