From e0b9f3b3cc3cdf3edcf0868e6c88e652455055fd Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 28 Jul 2021 18:54:21 +0200 Subject: [PATCH] Support storing return values in register places for all pass modes --- src/abi/mod.rs | 2 +- src/abi/returning.rs | 75 ++++++++++++++------------------------------ src/analyze.rs | 11 ------- 3 files changed, 24 insertions(+), 64 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 0478d4b19..13790409e 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -14,7 +14,7 @@ use cranelift_codegen::ir::{AbiParam, SigRef}; use self::pass_mode::*; use crate::prelude::*; -pub(crate) use self::returning::{can_return_to_ssa_var, codegen_return}; +pub(crate) use self::returning::codegen_return; fn clif_sig_from_fn_abi<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/src/abi/returning.rs b/src/abi/returning.rs index f9fc3992a..c1bdba43e 100644 --- a/src/abi/returning.rs +++ b/src/abi/returning.rs @@ -2,54 +2,9 @@ use crate::prelude::*; -use rustc_middle::ty::layout::FnAbiExt; -use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; +use rustc_target::abi::call::{ArgAbi, PassMode}; use smallvec::{smallvec, SmallVec}; -/// Can the given type be returned into an ssa var or does it need to be returned on the stack. -pub(crate) fn can_return_to_ssa_var<'tcx>( - fx: &FunctionCx<'_, '_, 'tcx>, - func: &mir::Operand<'tcx>, - args: &[mir::Operand<'tcx>], -) -> bool { - let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx)); - let fn_sig = - fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx)); - - // Handle special calls like instrinsics and empty drop glue. - let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() { - let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs) - .unwrap() - .unwrap() - .polymorphize(fx.tcx); - - match instance.def { - InstanceDef::Intrinsic(_) | InstanceDef::DropGlue(_, _) => { - return true; - } - _ => Some(instance), - } - } else { - None - }; - - let extra_args = &args[fn_sig.inputs().len()..]; - let extra_args = extra_args - .iter() - .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))) - .collect::>(); - let fn_abi = if let Some(instance) = instance { - FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args) - } else { - FnAbi::of_fn_ptr(&RevealAllLayoutCx(fx.tcx), fn_ty.fn_sig(fx.tcx), &extra_args) - }; - match fn_abi.ret.mode { - PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => true, - // FIXME Make it possible to return Indirect to an ssa var. - PassMode::Indirect { .. } => false, - } -} - /// Return a place where the return value of the current function can be written to. If necessary /// this adds an extra parameter pointing to where the return value needs to be stored. pub(super) fn codegen_return_param<'tcx>( @@ -104,16 +59,24 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( ret_place: Option>, f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option) -> Inst, ) { - let return_ptr = match ret_arg_abi.mode { - PassMode::Ignore => None, + let (ret_temp_place, return_ptr) = match ret_arg_abi.mode { + PassMode::Ignore => (None, None), PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => match ret_place { - Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)), - None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot + Some(ret_place) if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) => { + // This is an optimization to prevent unnecessary copies of the return value when + // the return place is already a memory place as opposed to a register. + // This match arm can be safely removed. + (None, Some(ret_place.to_ptr().get_addr(fx))) + } + _ => { + let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout); + (Some(place), Some(place.to_ptr().get_addr(fx))) + } }, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") } - PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None, + PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => (None, None), }; let call_inst = f(fx, return_ptr); @@ -149,7 +112,15 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( ret_place.write_cvalue(fx, result); } } - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {} + PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + if let (Some(ret_place), Some(ret_temp_place)) = (ret_place, ret_temp_place) { + // Both ret_place and ret_temp_place must be Some. If ret_place is None, this is + // a non-returning call. If ret_temp_place is None, it is not necessary to copy the + // return value. + let ret_temp_value = ret_temp_place.to_cvalue(fx); + ret_place.write_cvalue(fx, ret_temp_value); + } + } PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") } diff --git a/src/analyze.rs b/src/analyze.rs index efead2555..35b89358b 100644 --- a/src/analyze.rs +++ b/src/analyze.rs @@ -38,17 +38,6 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec { _ => {} } } - - match &bb.terminator().kind { - TerminatorKind::Call { destination, func, args, .. } => { - if let Some((dest_place, _dest_bb)) = destination { - if !crate::abi::can_return_to_ssa_var(fx, func, args) { - not_ssa(&mut flag_map, dest_place.local) - } - } - } - _ => {} - } } flag_map