Skip to content

Commit 70375e4

Browse files
committed
Make optimize_use_clone a MirPass.
1 parent 8be7f80 commit 70375e4

3 files changed

Lines changed: 70 additions & 66 deletions

File tree

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 3 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use std::iter;
33
use rustc_index::IndexVec;
44
use rustc_index::bit_set::DenseBitSet;
55
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
6-
use rustc_middle::mir::{Body, Local, UnwindTerminateReason, traversal};
6+
use rustc_middle::mir::{Local, UnwindTerminateReason, traversal};
77
use rustc_middle::mono::{InstantiationMode, MonoItem};
8-
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout};
8+
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
99
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitableExt};
1010
use rustc_middle::{bug, mir, span_bug};
1111
use rustc_span::ErrorGuaranteed;
@@ -194,7 +194,7 @@ pub fn lower_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
194194
let tcx = cx.tcx();
195195
let llfn = cx.get_fn(instance);
196196

197-
let mut mir = match MonoItem::Fn(instance).instantiation_mode(tcx) {
197+
let mir = match MonoItem::Fn(instance).instantiation_mode(tcx) {
198198
InstantiationMode::LocalCopy => tcx.build_codegen_mir(instance),
199199
InstantiationMode::GloballyShared { .. } => {
200200
rustc_mir_transform::build_codegen_mir(tcx, instance)
@@ -207,10 +207,6 @@ pub fn lower_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
207207
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
208208
debug!("fn_abi: {:?}", fn_abi);
209209

210-
if tcx.features().ergonomic_clones() {
211-
mir = tcx.arena.alloc(optimize_use_clone::<Bx>(cx, mir.clone()));
212-
}
213-
214210
let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, &mir);
215211

216212
let start_llbb = Bx::append_block(cx, llfn, "start");
@@ -325,65 +321,6 @@ pub fn lower_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
325321
}
326322
}
327323

328-
/// Replace `clone` calls that come from `use` statements with direct copies if possible.
329-
// FIXME: Move this function to mir::transform when post-mono MIR passes land.
330-
fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
331-
cx: &'a Bx::CodegenCx,
332-
mut mir: Body<'tcx>,
333-
) -> Body<'tcx> {
334-
let tcx = cx.tcx();
335-
336-
if tcx.features().ergonomic_clones() {
337-
for bb in mir.basic_blocks.as_mut() {
338-
let mir::TerminatorKind::Call {
339-
args,
340-
destination,
341-
target,
342-
call_source: mir::CallSource::Use,
343-
..
344-
} = &bb.terminator().kind
345-
else {
346-
continue;
347-
};
348-
349-
// CallSource::Use calls always use 1 argument.
350-
assert_eq!(args.len(), 1);
351-
let arg = &args[0];
352-
353-
// These types are easily available from locals, so check that before
354-
// doing DefId lookups to figure out what we're actually calling.
355-
let arg_ty = arg.node.ty(&mir.local_decls, tcx);
356-
357-
let ty::Ref(_region, inner_ty, mir::Mutability::Not) = *arg_ty.kind() else { continue };
358-
359-
if !tcx.type_is_copy_modulo_regions(cx.typing_env(), inner_ty) {
360-
continue;
361-
}
362-
363-
let Some(arg_place) = arg.node.place() else { continue };
364-
365-
let destination_block = target.unwrap();
366-
367-
bb.statements.push(mir::Statement::new(
368-
bb.terminator().source_info,
369-
mir::StatementKind::Assign(Box::new((
370-
*destination,
371-
mir::Rvalue::Use(
372-
mir::Operand::Copy(
373-
arg_place.project_deeper(&[mir::ProjectionElem::Deref], tcx),
374-
),
375-
mir::WithRetag::Yes,
376-
),
377-
))),
378-
));
379-
380-
bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block };
381-
}
382-
}
383-
384-
mir
385-
}
386-
387324
/// Produces, for each argument, a `Value` pointing at the
388325
/// argument's value. As arguments are places, these are always
389326
/// indirect.

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ declare_passes! {
167167
mod large_enums : EnumSizeOpt;
168168
mod lower_intrinsics : LowerIntrinsics;
169169
mod lower_slice_len : LowerSliceLenCalls;
170+
mod optimize_use_clone : OptimizeUseClone;
170171
mod match_branches : MatchBranchSimplification;
171172
mod mentioned_items : MentionedItems;
172173
mod multiple_return_terminators : MultipleReturnTerminators;
@@ -961,6 +962,7 @@ fn transform_to_codegen_mir<'tcx>(
961962
&instsimplify::SimplifyUbChecks::PostMono,
962963
&o1(simplify_branches::SimplifyConstCondition::PostMono),
963964
&o1(simplify::SimplifyCfg::PostMono),
965+
&optimize_use_clone::OptimizeUseClone,
964966
&add_call_guards::CriticalCallEdges,
965967
&deduce_param_attrs::RecoverDeducedParamAttrs,
966968
],
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! Optimize `Clone` calls created from `use` statements into direct copies for codegen MIR.
2+
3+
use rustc_middle::mir::*;
4+
use rustc_middle::ty::{self, TyCtxt};
5+
use rustc_session::Session;
6+
7+
use crate::deref_separator::deref_finder;
8+
9+
pub(super) struct OptimizeUseClone;
10+
11+
impl<'tcx> crate::MirPass<'tcx> for OptimizeUseClone {
12+
fn is_enabled(&self, sess: &Session) -> bool {
13+
sess.mir_opt_level() >= 4
14+
}
15+
16+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
17+
if !tcx.features().ergonomic_clones() {
18+
return;
19+
}
20+
21+
let typing_env = body.typing_env(tcx);
22+
let basic_blocks = body.basic_blocks.as_mut();
23+
for block in basic_blocks {
24+
let TerminatorKind::Call {
25+
args: [arg],
26+
destination,
27+
target: Some(target),
28+
call_source: CallSource::Use,
29+
..
30+
} = &block.terminator().kind
31+
else {
32+
continue;
33+
};
34+
35+
let arg_ty = arg.node.ty(&body.local_decls, tcx);
36+
let ty::Ref(_, inner_ty, Mutability::Not) = *arg_ty.kind() else {
37+
continue;
38+
};
39+
40+
if !tcx.type_is_copy_modulo_regions(typing_env, inner_ty) {
41+
continue;
42+
}
43+
44+
let Some(arg_place) = arg.node.place() else {
45+
continue;
46+
};
47+
48+
let target = *target;
49+
block.statements.push(Statement::new(
50+
block.terminator().source_info,
51+
StatementKind::Assign(Box::new((
52+
*destination,
53+
Rvalue::Use(Operand::Copy(tcx.mk_place_deref(arg_place)), WithRetag::Yes),
54+
))),
55+
));
56+
block.terminator_mut().kind = TerminatorKind::Goto { target };
57+
}
58+
59+
deref_finder(tcx, body, false);
60+
}
61+
62+
fn is_required(&self) -> bool {
63+
false
64+
}
65+
}

0 commit comments

Comments
 (0)