1 //! Return value handling
5 use rustc_middle::ty::layout::FnAbiExt;
6 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
7 use smallvec::{smallvec, SmallVec};
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, impl Module>,
12 func: &mir::Operand<'tcx>,
13 args: &[mir::Operand<'tcx>],
15 let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
18 .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
20 // Handle special calls like instrinsics and empty drop glue.
21 let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
22 let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
25 .polymorphize(fx.tcx);
28 InstanceDef::Intrinsic(_) | InstanceDef::DropGlue(_, _) => {
37 let extra_args = &args[fn_sig.inputs().len()..];
38 let extra_args = extra_args
40 .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))
42 let fn_abi = if let Some(instance) = instance {
43 FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args)
46 &RevealAllLayoutCx(fx.tcx),
51 match fn_abi.ret.mode {
52 PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) => true,
53 // FIXME Make it possible to return Cast and Indirect to an ssa var.
54 PassMode::Cast(_) | PassMode::Indirect { .. } => false,
58 /// Return a place where the return value of the current function can be written to. If necessary
59 /// this adds an extra parameter pointing to where the return value needs to be stored.
60 pub(super) fn codegen_return_param<'tcx>(
61 fx: &mut FunctionCx<'_, 'tcx, impl Module>,
62 ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>,
63 block_params_iter: &mut impl Iterator<Item = Value>,
65 let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
67 CPlace::no_place(fx.fn_abi.as_ref().unwrap().ret.layout),
70 PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => {
71 let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
73 super::make_local_place(
76 fx.fn_abi.as_ref().unwrap().ret.layout,
87 let ret_param = block_params_iter.next().unwrap();
88 assert_eq!(fx.bcx.func.dfg.value_type(ret_param), pointer_ty(fx.tcx));
91 Pointer::new(ret_param),
92 fx.fn_abi.as_ref().unwrap().ret.layout,
101 } => unreachable!("unsized return value"),
104 #[cfg(not(debug_assertions))]
107 #[cfg(debug_assertions)]
108 crate::abi::comments::add_arg_comment(
114 fx.fn_abi.as_ref().unwrap().ret.mode,
115 fx.fn_abi.as_ref().unwrap().ret.layout,
121 /// Invokes the closure with if necessary a value representing the return pointer. When the closure
122 /// returns the call return value(s) if any are written to the correct place.
123 pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>(
124 fx: &mut FunctionCx<'_, 'tcx, M>,
125 ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
126 ret_place: Option<CPlace<'tcx>>,
127 f: impl FnOnce(&mut FunctionCx<'_, 'tcx, M>, Option<Value>) -> (Inst, T),
129 let return_ptr = match ret_arg_abi.mode {
130 PassMode::Ignore => None,
135 } => match ret_place {
136 Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)),
137 None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot
141 extra_attrs: Some(_),
143 } => unreachable!("unsized return value"),
144 PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None,
147 let (call_inst, meta) = f(fx, return_ptr);
149 match ret_arg_abi.mode {
150 PassMode::Ignore => {}
151 PassMode::Direct(_) => {
152 if let Some(ret_place) = ret_place {
153 let ret_val = fx.bcx.inst_results(call_inst)[0];
154 ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout));
157 PassMode::Pair(_, _) => {
158 if let Some(ret_place) = ret_place {
159 let ret_val_a = fx.bcx.inst_results(call_inst)[0];
160 let ret_val_b = fx.bcx.inst_results(call_inst)[1];
161 ret_place.write_cvalue(
163 CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout),
167 PassMode::Cast(cast) => {
168 if let Some(ret_place) = ret_place {
171 .inst_results(call_inst)
174 .collect::<SmallVec<[Value; 2]>>();
176 super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
177 ret_place.write_cvalue(fx, result);
187 extra_attrs: Some(_),
189 } => unreachable!("unsized return value"),
195 /// Codegen a return instruction with the right return value(s) if any.
196 pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, impl Module>) {
197 match fx.fn_abi.as_ref().unwrap().ret.mode {
199 | PassMode::Indirect {
204 fx.bcx.ins().return_(&[]);
208 extra_attrs: Some(_),
210 } => unreachable!("unsized return value"),
211 PassMode::Direct(_) => {
212 let place = fx.get_local_place(RETURN_PLACE);
213 let ret_val = place.to_cvalue(fx).load_scalar(fx);
214 fx.bcx.ins().return_(&[ret_val]);
216 PassMode::Pair(_, _) => {
217 let place = fx.get_local_place(RETURN_PLACE);
218 let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
219 fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
221 PassMode::Cast(cast) => {
222 let place = fx.get_local_place(RETURN_PLACE);
223 let ret_val = place.to_cvalue(fx);
224 let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
225 fx.bcx.ins().return_(&ret_vals);