Don't copy ByRef passed types to local stack slot when not necessary

Eg when the local is immutable **and** the type is freeze.

This makes the simple raytracer runtime benchmark 1% faster than cg_llvm
without optimizations. Before it was 2% slower.

cc #691
cc #684
This commit is contained in:
bjorn3 2019-08-30 15:41:33 +02:00
parent 76d2e085db
commit 15b9834d7d
4 changed files with 49 additions and 1 deletions

View File

@ -202,3 +202,7 @@ fn get_sized_field_ref_from_unsized_type(u: &Unsized) -> &u8 {
fn get_unsized_field_ref_from_unsized_type(u: &Unsized) -> &str {
&u.1
}
pub fn reuse_byref_argument_storage(a: (u8, u16, u32)) -> u8 {
a.0
}

View File

@ -94,6 +94,15 @@ pub fn add_local_place_comments<'tcx>(
align.abi.bytes(),
align.pref.bytes(),
)),
CPlaceInner::Addr(_, _) => unreachable!(),
CPlaceInner::Addr(addr, None) => fx.add_global_comment(format!(
"reuse {:5} {:20} {:4}b {}, {} storage={}",
format!("{:?}", local),
format!("{:?}", ty),
size.bytes(),
align.abi.bytes(),
align.pref.bytes(),
addr,
)),
CPlaceInner::Addr(_, Some(_)) => unreachable!(),
}
}

View File

@ -282,6 +282,34 @@ pub fn codegen_fn_prelude(
.unwrap()
.contains(crate::analyze::Flags::NOT_SSA);
match arg_kind {
ArgKind::Normal(Some(val)) => {
if let Some(addr) = val.try_to_addr() {
let local_decl = &fx.mir.local_decls[local];
// v this ! is important
let internally_mutable = !val.layout().ty.is_freeze(
fx.tcx,
ParamEnv::reveal_all(),
local_decl.source_info.span,
);
if local_decl.mutability == mir::Mutability::Not && internally_mutable {
// We wont mutate this argument, so it is fine to borrow the backing storage
// of this argument, to prevent a copy.
let place = CPlace::for_addr(addr, val.layout());
#[cfg(debug_assertions)]
self::comments::add_local_place_comments(fx, place, local);
let prev_place = fx.local_map.insert(local, place);
debug_assert!(prev_place.is_none());
continue;
}
}
}
_ => {}
}
let place = local_place(fx, local, layout, is_ssa);
match arg_kind {

View File

@ -63,6 +63,13 @@ impl<'tcx> CValue<'tcx> {
}
}
pub fn try_to_addr(self) -> Option<Value> {
match self.0 {
CValueInner::ByRef(addr) => Some(addr),
CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => None,
}
}
/// Load a value with layout.abi of scalar
pub fn load_scalar<'a>(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> Value {
let layout = self.1;