Support storing return values in register places for all pass modes
This commit is contained in:
parent
b7881bb08d
commit
e0b9f3b3cc
3 changed files with 24 additions and 64 deletions
|
@ -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>,
|
||||
|
|
|
@ -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::<Vec<_>>();
|
||||
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<CPlace<'tcx>>,
|
||||
f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> 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")
|
||||
}
|
||||
|
|
|
@ -38,17 +38,6 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec<Local, SsaKind> {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue