Skip to content

Commit 077b864

Browse files
committed
Optimize codegen of use values that are copy post monomorphization
1 parent 038ca4b commit 077b864

File tree

1 file changed

+70
-7
lines changed
  • compiler/rustc_codegen_ssa/src/mir

1 file changed

+70
-7
lines changed

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ 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::{Local, UnwindTerminateReason, traversal};
6+
use rustc_middle::mir::{Body, Local, UnwindTerminateReason, traversal};
77
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout};
88
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
99
use rustc_middle::{bug, mir, span_bug};
@@ -171,18 +171,24 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
171171
assert!(!instance.args.has_infer());
172172

173173
let llfn = cx.get_fn(instance);
174+
let tcx = cx.tcx();
174175

175-
let mir = cx.tcx().instance_mir(instance.def);
176+
let mir = tcx.instance_mir(instance.def);
177+
let mir = instance.instantiate_mir_and_normalize_erasing_regions(
178+
tcx,
179+
ty::TypingEnv::fully_monomorphized(),
180+
ty::EarlyBinder::bind(mir.clone()),
181+
);
176182

177183
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
178184
debug!("fn_abi: {:?}", fn_abi);
179185

180-
if cx.tcx().codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
186+
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
181187
crate::mir::naked_asm::codegen_naked_asm::<Bx>(cx, &mir, instance);
182188
return;
183189
}
184190

185-
let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, mir);
191+
let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, &mir);
186192

187193
let start_llbb = Bx::append_block(cx, llfn, "start");
188194
let mut start_bx = Bx::build(cx, start_llbb);
@@ -194,7 +200,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
194200
}
195201

196202
let cleanup_kinds =
197-
base::wants_new_eh_instructions(cx.tcx().sess).then(|| analyze::cleanup_kinds(mir));
203+
base::wants_new_eh_instructions(tcx.sess).then(|| analyze::cleanup_kinds(&mir));
198204

199205
let cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>> =
200206
mir.basic_blocks
@@ -204,6 +210,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
204210
})
205211
.collect();
206212

213+
let mir = tcx.arena.alloc(optimize_use_clone::<Bx>(cx, mir));
214+
207215
let mut fx = FunctionCx {
208216
instance,
209217
mir,
@@ -217,7 +225,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
217225
cleanup_kinds,
218226
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
219227
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
220-
cold_blocks: find_cold_blocks(cx.tcx(), mir),
228+
cold_blocks: find_cold_blocks(tcx, mir),
221229
locals: locals::Locals::empty(),
222230
debug_context,
223231
per_local_var_debug_info: None,
@@ -233,7 +241,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
233241
fx.compute_per_local_var_debug_info(&mut start_bx).unzip();
234242
fx.per_local_var_debug_info = per_local_var_debug_info;
235243

236-
let traversal_order = traversal::mono_reachable_reverse_postorder(mir, cx.tcx(), instance);
244+
let traversal_order = traversal::mono_reachable_reverse_postorder(mir, tcx, instance);
237245
let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order);
238246

239247
// Allocate variable and temp allocas
@@ -310,6 +318,61 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
310318
}
311319
}
312320

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

0 commit comments

Comments
 (0)