]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_cranelift/src/abi/returning.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / compiler / rustc_codegen_cranelift / src / abi / returning.rs
CommitLineData
29967ef6
XL
1//! Return value handling
2
29967ef6
XL
3use crate::prelude::*;
4
94222f64 5use rustc_target::abi::call::{ArgAbi, PassMode};
5869c6ff 6use smallvec::{smallvec, SmallVec};
29967ef6 7
29967ef6
XL
8/// Return a place where the return value of the current function can be written to. If necessary
9/// this adds an extra parameter pointing to where the return value needs to be stored.
10pub(super) fn codegen_return_param<'tcx>(
6a06907d 11 fx: &mut FunctionCx<'_, '_, 'tcx>,
29967ef6 12 ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>,
5869c6ff 13 block_params_iter: &mut impl Iterator<Item = Value>,
29967ef6 14) -> CPlace<'tcx> {
5869c6ff 15 let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
94222f64 16 PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => {
29967ef6
XL
17 let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
18 (
5869c6ff
XL
19 super::make_local_place(
20 fx,
21 RETURN_PLACE,
22 fx.fn_abi.as_ref().unwrap().ret.layout,
23 is_ssa,
24 ),
25 smallvec![],
29967ef6
XL
26 )
27 }
6a06907d 28 PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
5869c6ff 29 let ret_param = block_params_iter.next().unwrap();
94222f64 30 assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type);
29967ef6 31 (
6a06907d 32 CPlace::for_ptr(Pointer::new(ret_param), fx.fn_abi.as_ref().unwrap().ret.layout),
5869c6ff 33 smallvec![ret_param],
29967ef6
XL
34 )
35 }
6a06907d
XL
36 PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
37 unreachable!("unsized return value")
38 }
29967ef6
XL
39 };
40
29967ef6
XL
41 crate::abi::comments::add_arg_comment(
42 fx,
43 "ret",
44 Some(RETURN_PLACE),
45 None,
5869c6ff
XL
46 &ret_param,
47 fx.fn_abi.as_ref().unwrap().ret.mode,
48 fx.fn_abi.as_ref().unwrap().ret.layout,
29967ef6
XL
49 );
50
51 ret_place
52}
53
54/// Invokes the closure with if necessary a value representing the return pointer. When the closure
55/// returns the call return value(s) if any are written to the correct place.
94222f64 56pub(super) fn codegen_with_call_return_arg<'tcx>(
6a06907d 57 fx: &mut FunctionCx<'_, '_, 'tcx>,
5869c6ff 58 ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
29967ef6 59 ret_place: Option<CPlace<'tcx>>,
94222f64
XL
60 f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> Inst,
61) {
62 let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
63 PassMode::Ignore => (None, None),
6a06907d 64 PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => match ret_place {
94222f64
XL
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 }
29967ef6 75 },
6a06907d
XL
76 PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
77 unreachable!("unsized return value")
78 }
94222f64 79 PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => (None, None),
29967ef6
XL
80 };
81
94222f64 82 let call_inst = f(fx, return_ptr);
29967ef6 83
5869c6ff
XL
84 match ret_arg_abi.mode {
85 PassMode::Ignore => {}
86 PassMode::Direct(_) => {
29967ef6
XL
87 if let Some(ret_place) = ret_place {
88 let ret_val = fx.bcx.inst_results(call_inst)[0];
5869c6ff 89 ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout));
29967ef6
XL
90 }
91 }
5869c6ff 92 PassMode::Pair(_, _) => {
29967ef6
XL
93 if let Some(ret_place) = ret_place {
94 let ret_val_a = fx.bcx.inst_results(call_inst)[0];
95 let ret_val_b = fx.bcx.inst_results(call_inst)[1];
5869c6ff
XL
96 ret_place.write_cvalue(
97 fx,
98 CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout),
99 );
29967ef6
XL
100 }
101 }
5869c6ff
XL
102 PassMode::Cast(cast) => {
103 if let Some(ret_place) = ret_place {
104 let results = fx
105 .bcx
106 .inst_results(call_inst)
cdc7bbd5 107 .iter()
5869c6ff
XL
108 .copied()
109 .collect::<SmallVec<[Value; 2]>>();
110 let result =
111 super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
112 ret_place.write_cvalue(fx, result);
113 }
114 }
94222f64
XL
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 }
6a06907d
XL
124 PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
125 unreachable!("unsized return value")
126 }
29967ef6 127 }
29967ef6
XL
128}
129
130/// Codegen a return instruction with the right return value(s) if any.
6a06907d 131pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
5869c6ff 132 match fx.fn_abi.as_ref().unwrap().ret.mode {
6a06907d 133 PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
29967ef6
XL
134 fx.bcx.ins().return_(&[]);
135 }
6a06907d
XL
136 PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
137 unreachable!("unsized return value")
138 }
5869c6ff 139 PassMode::Direct(_) => {
29967ef6
XL
140 let place = fx.get_local_place(RETURN_PLACE);
141 let ret_val = place.to_cvalue(fx).load_scalar(fx);
142 fx.bcx.ins().return_(&[ret_val]);
143 }
5869c6ff 144 PassMode::Pair(_, _) => {
29967ef6
XL
145 let place = fx.get_local_place(RETURN_PLACE);
146 let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
147 fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
148 }
5869c6ff
XL
149 PassMode::Cast(cast) => {
150 let place = fx.get_local_place(RETURN_PLACE);
151 let ret_val = place.to_cvalue(fx);
152 let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
153 fx.bcx.ins().return_(&ret_vals);
154 }
29967ef6
XL
155 }
156}