Skip to content

Commit e4c8ee7

Browse files
committed
Auto merge of rust-lang#128299 - DianQK:clone-copy, r=<try>
Simplify the canonical clone method and the copy-like forms to copy Fixes rust-lang#128081. Currently being blocked by rust-lang#128265. `@rustbot` label +S-blocked r? `@saethlin`
2 parents 0bb6fec + 31a1608 commit e4c8ee7

File tree

101 files changed

+1109
-183
lines changed

Some content is hidden

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

101 files changed

+1109
-183
lines changed

compiler/rustc_index/src/vec.rs

+10
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ impl<I: Idx, T> IndexVec<I, T> {
190190
let min_new_len = elem.index() + 1;
191191
self.raw.resize_with(min_new_len, fill_value);
192192
}
193+
194+
#[inline]
195+
pub fn reset_all(&mut self, elem: T)
196+
where
197+
T: Copy,
198+
{
199+
for e in self.raw.iter_mut() {
200+
*e = elem;
201+
}
202+
}
193203
}
194204

195205
/// `IndexVec` is often used as a map, so it provides some map-like APIs.

compiler/rustc_mir_transform/src/instsimplify.rs

+108-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::simplify::simplify_duplicate_switch_targets;
44
use crate::take_array;
55
use rustc_ast::attr;
66
use rustc_hir::LangItem;
7+
use rustc_index::IndexVec;
78
use rustc_middle::bug;
89
use rustc_middle::mir::*;
910
use rustc_middle::ty::layout;
@@ -13,9 +14,25 @@ use rustc_span::sym;
1314
use rustc_span::symbol::Symbol;
1415
use rustc_target::spec::abi::Abi;
1516

16-
pub struct InstSimplify;
17+
pub enum InstSimplify {
18+
BeforeInline,
19+
AfterSimplifyCfg,
20+
}
21+
22+
impl InstSimplify {
23+
pub fn name(&self) -> &'static str {
24+
match self {
25+
InstSimplify::BeforeInline => "InstSimplify-before-inline",
26+
InstSimplify::AfterSimplifyCfg => "InstSimplify-after-simplifycfg",
27+
}
28+
}
29+
}
1730

1831
impl<'tcx> MirPass<'tcx> for InstSimplify {
32+
fn name(&self) -> &'static str {
33+
self.name()
34+
}
35+
1936
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
2037
sess.mir_opt_level() > 0
2138
}
@@ -44,8 +61,8 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
4461
_ => {}
4562
}
4663
}
47-
4864
ctx.simplify_primitive_clone(block.terminator.as_mut().unwrap(), &mut block.statements);
65+
ctx.simplify_copy_like(&mut block.statements);
4966
ctx.simplify_intrinsic_assert(block.terminator.as_mut().unwrap());
5067
ctx.simplify_nounwind_call(block.terminator.as_mut().unwrap());
5168
simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
@@ -191,6 +208,95 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
191208
}
192209
}
193210

211+
/// Transform `Aggregate(Adt, [(*_1).0, (*_1).1])` ==> `Copy(*_1)`.
212+
/// This comes from the simplification of the clone method by `simplify_primitive_clone`.
213+
fn simplify_copy_like(&self, statements: &mut Vec<Statement<'tcx>>) {
214+
let mut assignments = IndexVec::from_elem(None::<Place<'tcx>>, self.local_decls);
215+
for statement in statements {
216+
match statement.kind {
217+
StatementKind::Assign(box (dest, ref mut rvalue)) => {
218+
if let Rvalue::Aggregate(_, fields) = rvalue {
219+
let mut from_local = None;
220+
if fields.iter_enumerated().all(|(index, field)| {
221+
let Some(from_place) = field
222+
.place()
223+
.and_then(|p| p.as_local())
224+
.and_then(|l| assignments[l])
225+
else {
226+
return false;
227+
};
228+
// All fields must come from the same local.
229+
if let Some(from_local) = from_local {
230+
if from_place.local != from_local {
231+
return false;
232+
}
233+
} else {
234+
// We can only copy the same type.
235+
let Some(from_ty) =
236+
self.local_decls[from_place.local].ty.builtin_deref(false)
237+
else {
238+
return false;
239+
};
240+
let dest_ty = dest.ty(self.local_decls, self.tcx).ty;
241+
if dest_ty != from_ty {
242+
return false;
243+
};
244+
from_local = Some(from_place.local);
245+
}
246+
// For more complex scenarios, we expect to get this simplified projection within a complete pipeline.
247+
let [ProjectionElem::Deref, ProjectionElem::Field(from_index, _)] =
248+
*from_place.projection.as_slice()
249+
else {
250+
return false;
251+
};
252+
from_index == index
253+
}) {
254+
if let Some(local) = from_local {
255+
if self.should_simplify(&statement.source_info, rvalue) {
256+
*rvalue = Rvalue::Use(Operand::Copy(Place {
257+
local,
258+
projection: self
259+
.tcx
260+
.mk_place_elems(&[ProjectionElem::Deref]),
261+
}));
262+
}
263+
}
264+
}
265+
}
266+
// Collect available assignments, including those transformed from `Aggregate`.
267+
if let Some(local) = dest.as_local() {
268+
assignments[local] = if let Rvalue::Use(operand) = rvalue
269+
&& let Some(place) = operand.place()
270+
{
271+
if let Some(rvalue_local) = place.as_local() {
272+
let place = assignments[rvalue_local];
273+
if operand.is_move() {
274+
assignments[rvalue_local] = None;
275+
}
276+
place
277+
} else {
278+
Some(place)
279+
}
280+
} else {
281+
// This assignment generally comes from debuginfo (e.g., Ref),
282+
// but we still need to check if a local is being overridden.
283+
None
284+
};
285+
} else {
286+
// We don't handle projection, so we drop all previous assignments.
287+
assignments.reset_all(None);
288+
}
289+
}
290+
StatementKind::StorageLive(_)
291+
| StatementKind::StorageDead(_)
292+
| StatementKind::Nop => {}
293+
_ => {
294+
assignments.reset_all(None);
295+
}
296+
}
297+
}
298+
}
299+
194300
fn simplify_cast(&self, rvalue: &mut Rvalue<'tcx>) {
195301
if let Rvalue::Cast(kind, operand, cast_ty) = rvalue {
196302
let operand_ty = operand.ty(self.local_decls, self.tcx);

compiler/rustc_mir_transform/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
572572
// Has to be done before inlining, otherwise actual call will be almost always inlined.
573573
// Also simple, so can just do first
574574
&lower_slice_len::LowerSliceLenCalls,
575+
// Perform instsimplify before inline to eliminate some trivial calls (like clone shims).
576+
&instsimplify::InstSimplify::BeforeInline,
575577
// Perform inlining, which may add a lot of code.
576578
&inline::Inline,
577579
// Code from other crates may have storage markers, so this needs to happen after inlining.
@@ -591,7 +593,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
591593
&match_branches::MatchBranchSimplification,
592594
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
593595
&multiple_return_terminators::MultipleReturnTerminators,
594-
&instsimplify::InstSimplify,
596+
// After simplifycfg, it allows us to discover new opportunities for peephole optimizations.
597+
&instsimplify::InstSimplify::AfterSimplifyCfg,
595598
&simplify::SimplifyLocals::BeforeConstProp,
596599
&dead_store_elimination::DeadStoreElimination::Initial,
597600
&gvn::GVN,

compiler/rustc_mir_transform/src/shim.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
154154
&deref_separator::Derefer,
155155
&remove_noop_landing_pads::RemoveNoopLandingPads,
156156
&simplify::SimplifyCfg::MakeShim,
157-
&instsimplify::InstSimplify,
157+
&instsimplify::InstSimplify::BeforeInline,
158158
&abort_unwinding_calls::AbortUnwindingCalls,
159159
&add_call_guards::CriticalCallEdges,
160160
],

tests/codegen/clone_as_copy.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//@ revisions: DEBUGINFO NODEBUGINFO
2+
//@ compile-flags: -O -Cno-prepopulate-passes
3+
//@ [DEBUGINFO] compile-flags: -Cdebuginfo=full
4+
5+
// From https://github.com/rust-lang/rust/issues/128081.
6+
// Ensure that we only generate a memcpy instruction.
7+
8+
#![crate_type = "lib"]
9+
10+
#[derive(Clone)]
11+
struct SubCloneAndCopy {
12+
v1: u32,
13+
v2: u32,
14+
}
15+
16+
#[derive(Clone)]
17+
struct CloneOnly {
18+
v1: u8,
19+
v2: u8,
20+
v3: u8,
21+
v4: u8,
22+
v5: u8,
23+
v6: u8,
24+
v7: u8,
25+
v8: u8,
26+
v9: u8,
27+
v_sub: SubCloneAndCopy,
28+
v_large: [u8; 256],
29+
}
30+
31+
// CHECK-LABEL: define {{.*}}@clone_only(
32+
#[no_mangle]
33+
pub fn clone_only(v: &CloneOnly) -> CloneOnly {
34+
// CHECK-NOT: call {{.*}}clone
35+
// CHECK-NOT: store i8
36+
// CHECK-NOT: store i32
37+
// CHECK: call void @llvm.memcpy
38+
// CHECK-NEXT: ret void
39+
v.clone()
40+
}

tests/incremental/hashes/call_expressions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ pub fn change_to_ufcs() {
162162
}
163163

164164
#[cfg(not(any(cfail1,cfail4)))]
165-
#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,typeck")]
165+
#[rustc_clean(cfg="cfail2", except="opt_hir_owner_nodes,optimized_mir,typeck")]
166166
#[rustc_clean(cfg="cfail3")]
167167
#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,optimized_mir,typeck")]
168168
#[rustc_clean(cfg="cfail6")]

tests/mir-opt/const_prop/slice_len.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@ test-mir-pass: GVN
2-
//@ compile-flags: -Zmir-enable-passes=+InstSimplify -Zdump-mir-exclude-alloc-bytes
2+
//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg -Zdump-mir-exclude-alloc-bytes
33
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
44
// EMIT_MIR_FOR_EACH_BIT_WIDTH
55

tests/mir-opt/dataflow-const-prop/slice_len.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
22
//@ test-mir-pass: DataflowConstProp
3-
//@ compile-flags: -Zmir-enable-passes=+InstSimplify
3+
//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg
44
// EMIT_MIR_FOR_EACH_BIT_WIDTH
55

66
// EMIT_MIR slice_len.main.DataflowConstProp.diff

tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121
bb0: {
2222
StorageLive(_2);
2323
StorageLive(_3);
24-
_3 = &(*_1);
24+
_3 = _1;
2525
_2 = <Q as Query>::cache::<T>(move _3) -> [return: bb1, unwind unreachable];
2626
}
2727

2828
bb1: {
2929
StorageDead(_3);
3030
StorageLive(_4);
31-
_4 = &(*_2);
31+
_4 = _2;
3232
- _0 = try_execute_query::<<Q as Query>::C>(move _4) -> [return: bb2, unwind unreachable];
3333
+ StorageLive(_5);
3434
+ _5 = _4 as &dyn Cache<V = <Q as Query>::V> (PointerCoercion(Unsize));

tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121
bb0: {
2222
StorageLive(_2);
2323
StorageLive(_3);
24-
_3 = &(*_1);
24+
_3 = _1;
2525
_2 = <Q as Query>::cache::<T>(move _3) -> [return: bb1, unwind continue];
2626
}
2727

2828
bb1: {
2929
StorageDead(_3);
3030
StorageLive(_4);
31-
_4 = &(*_2);
31+
_4 = _2;
3232
- _0 = try_execute_query::<<Q as Query>::C>(move _4) -> [return: bb2, unwind continue];
3333
+ StorageLive(_5);
3434
+ _5 = _4 as &dyn Cache<V = <Q as Query>::V> (PointerCoercion(Unsize));

tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.panic-abort.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
bb0: {
1010
StorageLive(_2);
11-
_2 = &(*_1);
11+
_2 = _1;
1212
_0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> [return: bb1, unwind unreachable];
1313
}
1414

tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
bb0: {
1010
StorageLive(_2);
11-
_2 = &(*_1);
11+
_2 = _1;
1212
_0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> [return: bb1, unwind continue];
1313
}
1414

tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
bb0: {
1414
StorageLive(_2);
1515
StorageLive(_3);
16-
_3 = &(*_1);
16+
_3 = _1;
1717
_2 = move _3 as &dyn Cache<V = <C as Cache>::V> (PointerCoercion(Unsize));
1818
StorageDead(_3);
1919
- _0 = mk_cycle::<<C as Cache>::V>(move _2) -> [return: bb1, unwind unreachable];

tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
bb0: {
1414
StorageLive(_2);
1515
StorageLive(_3);
16-
_3 = &(*_1);
16+
_3 = _1;
1717
_2 = move _3 as &dyn Cache<V = <C as Cache>::V> (PointerCoercion(Unsize));
1818
StorageDead(_3);
1919
- _0 = mk_cycle::<<C as Cache>::V>(move _2) -> [return: bb1, unwind continue];

tests/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ fn foo(_1: T, _2: &i32) -> i32 {
2626
_4 = &_3;
2727
StorageLive(_5);
2828
StorageLive(_6);
29-
_6 = &(*_2);
29+
_6 = _2;
3030
StorageLive(_7);
31-
_7 = &(*_2);
31+
_7 = _2;
3232
_5 = (move _6, move _7);
3333
StorageLive(_8);
3434
_8 = move (_5.0: &i32);

tests/mir-opt/inline/inline_retag.bar.Inline.after.mir

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ fn bar() -> bool {
3131
StorageLive(_4);
3232
_10 = const bar::promoted[1];
3333
Retag(_10);
34-
_4 = &(*_10);
35-
_3 = &(*_4);
34+
_4 = _10;
35+
_3 = _4;
3636
StorageLive(_6);
3737
StorageLive(_7);
3838
_9 = const bar::promoted[0];
3939
Retag(_9);
40-
_7 = &(*_9);
41-
_6 = &(*_7);
40+
_7 = _9;
41+
_6 = _7;
4242
Retag(_3);
4343
Retag(_6);
4444
StorageLive(_11);

tests/mir-opt/inline/inline_trait_method.test.Inline.after.panic-abort.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ fn test(_1: &dyn X) -> u32 {
77

88
bb0: {
99
StorageLive(_2);
10-
_2 = &(*_1);
10+
_2 = _1;
1111
_0 = <dyn X as X>::y(move _2) -> [return: bb1, unwind unreachable];
1212
}
1313

tests/mir-opt/inline/inline_trait_method.test.Inline.after.panic-unwind.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ fn test(_1: &dyn X) -> u32 {
77

88
bb0: {
99
StorageLive(_2);
10-
_2 = &(*_1);
10+
_2 = _1;
1111
_0 = <dyn X as X>::y(move _2) -> [return: bb1, unwind continue];
1212
}
1313

tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-abort.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ fn test2(_1: &dyn X) -> bool {
1212
bb0: {
1313
StorageLive(_2);
1414
StorageLive(_3);
15-
_3 = &(*_1);
16-
_2 = move _3 as &dyn X (PointerCoercion(Unsize));
15+
_3 = _1;
16+
_2 = move _3;
1717
StorageDead(_3);
1818
_0 = <dyn X as X>::y(move _2) -> [return: bb1, unwind unreachable];
1919
}

tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ fn test2(_1: &dyn X) -> bool {
1212
bb0: {
1313
StorageLive(_2);
1414
StorageLive(_3);
15-
_3 = &(*_1);
16-
_2 = move _3 as &dyn X (PointerCoercion(Unsize));
15+
_3 = _1;
16+
_2 = move _3;
1717
StorageDead(_3);
1818
_0 = <dyn X as X>::y(move _2) -> [return: bb1, unwind continue];
1919
}

0 commit comments

Comments
 (0)