|
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