|
2 | 2 |
|
3 | 3 | use crate::prelude::*; |
4 | 4 |
|
5 | | -use rustc_middle::ty::layout::FnAbiExt; |
6 | | -use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; |
| 5 | +use rustc_target::abi::call::{ArgAbi, PassMode}; |
7 | 6 | use smallvec::{smallvec, SmallVec}; |
8 | 7 |
|
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 | | - |
53 | 8 | /// Return a place where the return value of the current function can be written to. If necessary |
54 | 9 | /// this adds an extra parameter pointing to where the return value needs to be stored. |
55 | 10 | pub(super) fn codegen_return_param<'tcx>( |
@@ -104,16 +59,24 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( |
104 | 59 | ret_place: Option<CPlace<'tcx>>, |
105 | 60 | f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> Inst, |
106 | 61 | ) { |
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), |
109 | 64 | 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 | + } |
112 | 75 | }, |
113 | 76 | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { |
114 | 77 | unreachable!("unsized return value") |
115 | 78 | } |
116 | | - PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None, |
| 79 | + PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => (None, None), |
117 | 80 | }; |
118 | 81 |
|
119 | 82 | let call_inst = f(fx, return_ptr); |
@@ -149,7 +112,15 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( |
149 | 112 | ret_place.write_cvalue(fx, result); |
150 | 113 | } |
151 | 114 | } |
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 | + } |
153 | 124 | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { |
154 | 125 | unreachable!("unsized return value") |
155 | 126 | } |
|
0 commit comments