Skip to content

Commit

Permalink
Auto merge of #109025 - cjgillot:refprop-dbg, r=JakobDegen
Browse files Browse the repository at this point in the history
Enable MIR reference propagation by default
  • Loading branch information
bors committed Jul 14, 2023
2 parents 5767cad + f993c6d commit 079e544
Show file tree
Hide file tree
Showing 43 changed files with 704 additions and 902 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,14 +553,14 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
&const_goto::ConstGoto,
&remove_unneeded_drops::RemoveUnneededDrops,
&ref_prop::ReferencePropagation,
&sroa::ScalarReplacementOfAggregates,
&match_branches::MatchBranchSimplification,
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
&multiple_return_terminators::MultipleReturnTerminators,
&instsimplify::InstSimplify,
&simplify::SimplifyLocals::BeforeConstProp,
&copy_prop::CopyProp,
&ref_prop::ReferencePropagation,
// Perform `SeparateConstSwitch` after SSA-based analyses, as cloning blocks may
// destroy the SSA property. It should still happen before const-propagation, so the
// latter pass will leverage the created opportunities.
Expand Down
42 changes: 27 additions & 15 deletions compiler/rustc_mir_transform/src/ref_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub struct ReferencePropagation;

impl<'tcx> MirPass<'tcx> for ReferencePropagation {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 4
sess.mir_opt_level() >= 2
}

#[instrument(level = "trace", skip(self, tcx, body))]
Expand Down Expand Up @@ -355,7 +355,10 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
}

fn visit_var_debug_info(&mut self, debuginfo: &mut VarDebugInfo<'tcx>) {
if let VarDebugInfoContents::Place(ref mut place) = debuginfo.value
// If the debuginfo is a pointer to another place:
// - if it's a reborrow, see through it;
// - if it's a direct borrow, increase `debuginfo.references`.
while let VarDebugInfoContents::Place(ref mut place) = debuginfo.value
&& place.projection.is_empty()
&& let Value::Pointer(target, _) = self.targets[place.local]
&& target.projection.iter().all(|p| p.can_use_in_debuginfo())
Expand All @@ -369,28 +372,37 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
debuginfo.references = references;
*place = target;
self.any_replacement = true;
} else {
break
}
}

// Simplify eventual projections left inside `debuginfo`.
self.super_var_debug_info(debuginfo);
}

fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
if place.projection.first() != Some(&PlaceElem::Deref) {
return;
}

loop {
if let Value::Pointer(target, _) = self.targets[place.local] {
let perform_opt = matches!(ctxt, PlaceContext::NonUse(_))
|| self.allowed_replacements.contains(&(target.local, loc));

if perform_opt {
*place = target.project_deeper(&place.projection[1..], self.tcx);
self.any_replacement = true;
continue;
if place.projection.first() != Some(&PlaceElem::Deref) {
return;
}

let Value::Pointer(target, _) = self.targets[place.local] else { return };

let perform_opt = match ctxt {
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
target.projection.iter().all(|p| p.can_use_in_debuginfo())
}
PlaceContext::NonUse(_) => true,
_ => self.allowed_replacements.contains(&(target.local, loc)),
};

if !perform_opt {
return;
}

break;
*place = target.project_deeper(&place.projection[1..], self.tcx);
self.any_replacement = true;
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/codegen/iter-repeat-n-trivial-drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCop

// CHECK: [[EMPTY]]:
// CHECK-NOT: br
// CHECK: phi i16 [ undef, %start ], [ %[[VAL]], %[[NOT_EMPTY]] ]
// CHECK: phi i16 [ %[[VAL]], %[[NOT_EMPTY]] ], [ undef, %start ]
// CHECK-NOT: br
// CHECK: ret

Expand Down
16 changes: 10 additions & 6 deletions tests/codegen/slice-init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub fn zero_sized_elem() {
// CHECK-NOT: br label %repeat_loop_header{{.*}}
// CHECK-NOT: call void @llvm.memset.p0
let x = [(); 4];
drop(&x);
opaque(&x);
}

// CHECK-LABEL: @zero_len_array
Expand All @@ -17,7 +17,7 @@ pub fn zero_len_array() {
// CHECK-NOT: br label %repeat_loop_header{{.*}}
// CHECK-NOT: call void @llvm.memset.p0
let x = [4; 0];
drop(&x);
opaque(&x);
}

// CHECK-LABEL: @byte_array
Expand All @@ -26,7 +26,7 @@ pub fn byte_array() {
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 7, i{{[0-9]+}} 4
// CHECK-NOT: br label %repeat_loop_header{{.*}}
let x = [7u8; 4];
drop(&x);
opaque(&x);
}

#[allow(dead_code)]
Expand All @@ -42,7 +42,7 @@ pub fn byte_enum_array() {
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 {{.*}}, i{{[0-9]+}} 4
// CHECK-NOT: br label %repeat_loop_header{{.*}}
let x = [Init::Memset; 4];
drop(&x);
opaque(&x);
}

// CHECK-LABEL: @zeroed_integer_array
Expand All @@ -51,7 +51,7 @@ pub fn zeroed_integer_array() {
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 0, i{{[0-9]+}} 16
// CHECK-NOT: br label %repeat_loop_header{{.*}}
let x = [0u32; 4];
drop(&x);
opaque(&x);
}

// CHECK-LABEL: @nonzero_integer_array
Expand All @@ -60,5 +60,9 @@ pub fn nonzero_integer_array() {
// CHECK: br label %repeat_loop_header{{.*}}
// CHECK-NOT: call void @llvm.memset.p0
let x = [0x1a_2b_3c_4d_u32; 4];
drop(&x);
opaque(&x);
}

// Use an opaque function to prevent rustc from removing useless drops.
#[inline(never)]
pub fn opaque(_: impl Sized) {}
32 changes: 16 additions & 16 deletions tests/codegen/slice-ref-equality.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,48 +44,48 @@ pub fn is_zero_array(data: &[u8; 4]) -> bool {
// equality for non-byte types also just emit a `bcmp`, not a loop.

// CHECK-LABEL: @eq_slice_of_nested_u8(
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1
// CHECK-SAME: [[USIZE]] noundef %3
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
// CHECK-SAME: [[USIZE]] noundef %y.1
#[no_mangle]
fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool {
// CHECK: icmp eq [[USIZE]] %1, %3
// CHECK: %[[BYTES:.+]] = mul nsw [[USIZE]] %1, 3
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
// CHECK: %[[BYTES:.+]] = mul nsw [[USIZE]] %x.1, 3
// CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i8\*|ptr}}
// CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
x == y
}

// CHECK-LABEL: @eq_slice_of_i32(
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1
// CHECK-SAME: [[USIZE]] noundef %3
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
// CHECK-SAME: [[USIZE]] noundef %y.1
#[no_mangle]
fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool {
// CHECK: icmp eq [[USIZE]] %1, %3
// CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
// CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 2
// CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}}
// CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
x == y
}

// CHECK-LABEL: @eq_slice_of_nonzero(
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1
// CHECK-SAME: [[USIZE]] noundef %3
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
// CHECK-SAME: [[USIZE]] noundef %y.1
#[no_mangle]
fn eq_slice_of_nonzero(x: &[NonZeroU32], y: &[NonZeroU32]) -> bool {
// CHECK: icmp eq [[USIZE]] %1, %3
// CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
// CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 2
// CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}}
// CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
x == y
}

// CHECK-LABEL: @eq_slice_of_option_of_nonzero(
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1
// CHECK-SAME: [[USIZE]] noundef %3
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
// CHECK-SAME: [[USIZE]] noundef %y.1
#[no_mangle]
fn eq_slice_of_option_of_nonzero(x: &[Option<NonZeroI16>], y: &[Option<NonZeroI16>]) -> bool {
// CHECK: icmp eq [[USIZE]] %1, %3
// CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 1
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
// CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 1
// CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i16\*|ptr}}
// CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
x == y
Expand Down
2 changes: 1 addition & 1 deletion tests/incremental/hashes/call_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ pub fn change_to_ufcs() {
}

#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
#[rustc_clean(cfg="cfail6")]
Expand Down
2 changes: 1 addition & 1 deletion tests/mir-opt/casts.redundant.InstSimplify.diff
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
let mut _2: *const &u8;
let mut _3: *const &u8;
scope 1 (inlined generic_cast::<&u8, &u8>) {
debug x => _3;
debug x => _1;
}

bb0: {
Expand Down
2 changes: 2 additions & 0 deletions tests/mir-opt/copy-prop/mutate_through_pointer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// unit-test: CopyProp
//
// This attempts to mutate `a` via a pointer derived from `addr_of!(a)`. That is UB
// according to Miri. However, the decision to make this UB - and to allow
// rustc to rely on that fact for the purpose of optimizations - has not been
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
let mut _2: std::option::Option<T>;
+ scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
+ debug self => _2;
+ let mut _3: &std::option::Option<T>;
+ let mut _4: isize;
+ let mut _3: isize;
+ scope 2 {
+ debug val => _0;
+ }
Expand All @@ -21,17 +20,16 @@
+ }
+ }
+ scope 4 (inlined Option::<T>::is_some) {
+ debug self => _3;
+ debug self => &_2;
+ }
+ }

bb0: {
StorageLive(_2);
_2 = move _1;
- _0 = Option::<T>::unwrap_unchecked(move _2) -> [return: bb1, unwind unreachable];
+ StorageLive(_3);
+ _4 = discriminant(_2);
+ switchInt(move _4) -> [1: bb2, otherwise: bb1];
+ _3 = discriminant(_2);
+ switchInt(move _3) -> [1: bb2, otherwise: bb1];
}

bb1: {
Expand All @@ -40,7 +38,6 @@
+
+ bb2: {
+ _0 = move ((_2 as Some).0: T);
+ StorageDead(_3);
StorageDead(_2);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
let mut _2: std::option::Option<T>;
+ scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
+ debug self => _2;
+ let mut _3: &std::option::Option<T>;
+ let mut _4: isize;
+ let mut _3: isize;
+ scope 2 {
+ debug val => _0;
+ }
Expand All @@ -21,17 +20,16 @@
+ }
+ }
+ scope 4 (inlined Option::<T>::is_some) {
+ debug self => _3;
+ debug self => &_2;
+ }
+ }

bb0: {
StorageLive(_2);
_2 = move _1;
- _0 = Option::<T>::unwrap_unchecked(move _2) -> [return: bb1, unwind: bb2];
+ StorageLive(_3);
+ _4 = discriminant(_2);
+ switchInt(move _4) -> [1: bb2, otherwise: bb1];
+ _3 = discriminant(_2);
+ switchInt(move _3) -> [1: bb2, otherwise: bb1];
}

bb1: {
Expand All @@ -44,7 +42,6 @@
- resume;
+ bb2: {
+ _0 = move ((_2 as Some).0: T);
+ StorageDead(_3);
+ StorageDead(_2);
+ return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
debug self => _1;
let mut _2: isize;
let mut _3: &std::option::Option<T>;
scope 2 {
debug val => _0;
}
Expand All @@ -19,19 +18,17 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
}
}
scope 4 (inlined Option::<T>::is_some) {
debug self => _3;
debug self => &_1;
}
}

bb0: {
StorageLive(_3);
_2 = discriminant(_1);
switchInt(move _2) -> [1: bb1, otherwise: bb2];
}

bb1: {
_0 = move ((_1 as Some).0: T);
StorageDead(_3);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
debug self => _1;
let mut _2: isize;
let mut _3: &std::option::Option<T>;
scope 2 {
debug val => _0;
}
Expand All @@ -19,19 +18,17 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
}
}
scope 4 (inlined Option::<T>::is_some) {
debug self => _3;
debug self => &_1;
}
}

bb0: {
StorageLive(_3);
_2 = discriminant(_1);
switchInt(move _2) -> [1: bb1, otherwise: bb2];
}

bb1: {
_0 = move ((_1 as Some).0: T);
StorageDead(_3);
return;
}

Expand Down
Loading

0 comments on commit 079e544

Please sign in to comment.