Skip to content

Commit e0b9f3b

Browse files
committed
Support storing return values in register places for all pass modes
1 parent b7881bb commit e0b9f3b

File tree

3 files changed

+24
-64
lines changed

3 files changed

+24
-64
lines changed

src/abi/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use cranelift_codegen::ir::{AbiParam, SigRef};
1414
use self::pass_mode::*;
1515
use crate::prelude::*;
1616

17-
pub(crate) use self::returning::{can_return_to_ssa_var, codegen_return};
17+
pub(crate) use self::returning::codegen_return;
1818

1919
fn clif_sig_from_fn_abi<'tcx>(
2020
tcx: TyCtxt<'tcx>,

src/abi/returning.rs

+23-52
Original file line numberDiff line numberDiff line change
@@ -2,54 +2,9 @@
22
33
use crate::prelude::*;
44

5-
use rustc_middle::ty::layout::FnAbiExt;
6-
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
5+
use rustc_target::abi::call::{ArgAbi, PassMode};
76
use smallvec::{smallvec, SmallVec};
87

9-
/// Can the given type be returned into an ssa var or does it need to be returned on the stack.
10-
pub(crate) fn can_return_to_ssa_var<'tcx>(
11-
fx: &FunctionCx<'_, '_, 'tcx>,
12-
func: &mir::Operand<'tcx>,
13-
args: &[mir::Operand<'tcx>],
14-
) -> bool {
15-
let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
16-
let fn_sig =
17-
fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
18-
19-
// Handle special calls like instrinsics and empty drop glue.
20-
let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
21-
let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
22-
.unwrap()
23-
.unwrap()
24-
.polymorphize(fx.tcx);
25-
26-
match instance.def {
27-
InstanceDef::Intrinsic(_) | InstanceDef::DropGlue(_, _) => {
28-
return true;
29-
}
30-
_ => Some(instance),
31-
}
32-
} else {
33-
None
34-
};
35-
36-
let extra_args = &args[fn_sig.inputs().len()..];
37-
let extra_args = extra_args
38-
.iter()
39-
.map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))
40-
.collect::<Vec<_>>();
41-
let fn_abi = if let Some(instance) = instance {
42-
FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args)
43-
} else {
44-
FnAbi::of_fn_ptr(&RevealAllLayoutCx(fx.tcx), fn_ty.fn_sig(fx.tcx), &extra_args)
45-
};
46-
match fn_abi.ret.mode {
47-
PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => true,
48-
// FIXME Make it possible to return Indirect to an ssa var.
49-
PassMode::Indirect { .. } => false,
50-
}
51-
}
52-
538
/// Return a place where the return value of the current function can be written to. If necessary
549
/// this adds an extra parameter pointing to where the return value needs to be stored.
5510
pub(super) fn codegen_return_param<'tcx>(
@@ -104,16 +59,24 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
10459
ret_place: Option<CPlace<'tcx>>,
10560
f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> Inst,
10661
) {
107-
let return_ptr = match ret_arg_abi.mode {
108-
PassMode::Ignore => None,
62+
let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
63+
PassMode::Ignore => (None, None),
10964
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => match ret_place {
110-
Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)),
111-
None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot
65+
Some(ret_place) if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) => {
66+
// This is an optimization to prevent unnecessary copies of the return value when
67+
// the return place is already a memory place as opposed to a register.
68+
// This match arm can be safely removed.
69+
(None, Some(ret_place.to_ptr().get_addr(fx)))
70+
}
71+
_ => {
72+
let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout);
73+
(Some(place), Some(place.to_ptr().get_addr(fx)))
74+
}
11275
},
11376
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
11477
unreachable!("unsized return value")
11578
}
116-
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None,
79+
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => (None, None),
11780
};
11881

11982
let call_inst = f(fx, return_ptr);
@@ -149,7 +112,15 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
149112
ret_place.write_cvalue(fx, result);
150113
}
151114
}
152-
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {}
115+
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
116+
if let (Some(ret_place), Some(ret_temp_place)) = (ret_place, ret_temp_place) {
117+
// Both ret_place and ret_temp_place must be Some. If ret_place is None, this is
118+
// a non-returning call. If ret_temp_place is None, it is not necessary to copy the
119+
// return value.
120+
let ret_temp_value = ret_temp_place.to_cvalue(fx);
121+
ret_place.write_cvalue(fx, ret_temp_value);
122+
}
123+
}
153124
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
154125
unreachable!("unsized return value")
155126
}

src/analyze.rs

-11
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,6 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec<Local, SsaKind> {
3838
_ => {}
3939
}
4040
}
41-
42-
match &bb.terminator().kind {
43-
TerminatorKind::Call { destination, func, args, .. } => {
44-
if let Some((dest_place, _dest_bb)) = destination {
45-
if !crate::abi::can_return_to_ssa_var(fx, func, args) {
46-
not_ssa(&mut flag_map, dest_place.local)
47-
}
48-
}
49-
}
50-
_ => {}
51-
}
5241
}
5342

5443
flag_map

0 commit comments

Comments
 (0)