Skip to content

Commit f05ea11

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

File tree

1 file changed

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

1 file changed

+81
-7
lines changed

compiler/rustc_codegen_ssa/src/mir/mod.rs

+81-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use std::iter;
22

3+
use rustc_hir as hir;
34
use rustc_index::IndexVec;
45
use rustc_index::bit_set::DenseBitSet;
56
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
6-
use rustc_middle::mir::{Local, UnwindTerminateReason, traversal};
7+
use rustc_middle::mir::{Body, Local, UnwindTerminateReason, traversal};
78
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout};
89
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
910
use rustc_middle::{bug, mir, span_bug};
@@ -171,18 +172,24 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
171172
assert!(!instance.args.has_infer());
172173

173174
let llfn = cx.get_fn(instance);
175+
let tcx = cx.tcx();
174176

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

177184
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
178185
debug!("fn_abi: {:?}", fn_abi);
179186

180-
if cx.tcx().codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
187+
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
181188
crate::mir::naked_asm::codegen_naked_asm::<Bx>(cx, &mir, instance);
182189
return;
183190
}
184191

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

187194
let start_llbb = Bx::append_block(cx, llfn, "start");
188195
let mut start_bx = Bx::build(cx, start_llbb);
@@ -194,7 +201,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
194201
}
195202

196203
let cleanup_kinds =
197-
base::wants_new_eh_instructions(cx.tcx().sess).then(|| analyze::cleanup_kinds(mir));
204+
base::wants_new_eh_instructions(tcx.sess).then(|| analyze::cleanup_kinds(&mir));
198205

199206
let cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>> =
200207
mir.basic_blocks
@@ -204,6 +211,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
204211
})
205212
.collect();
206213

214+
let mir = tcx.arena.alloc(optimize_use_clone(tcx, mir));
215+
207216
let mut fx = FunctionCx {
208217
instance,
209218
mir,
@@ -217,7 +226,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
217226
cleanup_kinds,
218227
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
219228
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
220-
cold_blocks: find_cold_blocks(cx.tcx(), mir),
229+
cold_blocks: find_cold_blocks(tcx, mir),
221230
locals: locals::Locals::empty(),
222231
debug_context,
223232
per_local_var_debug_info: None,
@@ -233,7 +242,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
233242
fx.compute_per_local_var_debug_info(&mut start_bx).unzip();
234243
fx.per_local_var_debug_info = per_local_var_debug_info;
235244

236-
let traversal_order = traversal::mono_reachable_reverse_postorder(mir, cx.tcx(), instance);
245+
let traversal_order = traversal::mono_reachable_reverse_postorder(mir, tcx, instance);
237246
let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order);
238247

239248
// Allocate variable and temp allocas
@@ -310,6 +319,71 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
310319
}
311320
}
312321

322+
// FIXME: Move this function to mir::transform when post-mono MIR passes land.
323+
fn optimize_use_clone<'tcx>(tcx: TyCtxt<'tcx>, mut mir: Body<'tcx>) -> Body<'tcx> {
324+
if tcx.features().ergonomic_clones() {
325+
for bb in mir.basic_blocks.as_mut() {
326+
let mir::TerminatorKind::Call {
327+
func,
328+
args,
329+
destination,
330+
target,
331+
call_source: mir::CallSource::Use,
332+
..
333+
} = &bb.terminator().kind
334+
else {
335+
continue;
336+
};
337+
338+
// It's definitely not a clone if there are multiple arguments
339+
let [arg] = &args[..] else { continue };
340+
341+
// These types are easily available from locals, so check that before
342+
// doing DefId lookups to figure out what we're actually calling.
343+
let arg_ty = arg.node.ty(&mir.local_decls, tcx);
344+
345+
// monomorphize
346+
// is already monomorphized
347+
// let arg_ty = instance.instantiate_mir_and_normalize_erasing_regions(
348+
// cx.tcx(),
349+
// cx.typing_env(),
350+
// ty::EarlyBinder::bind(arg_ty),
351+
// );
352+
353+
// Only bother looking more if it's easy to know what we're calling
354+
let Some((fn_def_id, _)) = func.const_fn_def() else { continue };
355+
356+
let ty::Ref(_region, inner_ty, mir::Mutability::Not) = *arg_ty.kind() else { continue };
357+
358+
if !inner_ty.is_trivially_pure_clone_copy() {
359+
continue;
360+
}
361+
362+
if !tcx.is_lang_item(fn_def_id, hir::LangItem::CloneFn) {
363+
continue;
364+
}
365+
366+
let Some(arg_place) = arg.node.place() else { continue };
367+
368+
let destination_block = target.unwrap();
369+
370+
bb.statements.push(mir::Statement {
371+
source_info: bb.terminator().source_info,
372+
kind: mir::StatementKind::Assign(Box::new((
373+
*destination,
374+
mir::Rvalue::Use(mir::Operand::Copy(
375+
arg_place.project_deeper(&[mir::ProjectionElem::Deref], tcx),
376+
)),
377+
))),
378+
});
379+
380+
bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block };
381+
}
382+
}
383+
384+
mir
385+
}
386+
313387
/// Produces, for each argument, a `Value` pointing at the
314388
/// argument's value. As arguments are places, these are always
315389
/// indirect.

0 commit comments

Comments
 (0)