]>
Commit | Line | Data |
---|---|---|
29967ef6 XL |
1 | //! Return value handling |
2 | ||
29967ef6 XL |
3 | use crate::prelude::*; |
4 | ||
94222f64 | 5 | use rustc_target::abi::call::{ArgAbi, PassMode}; |
5869c6ff | 6 | use 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. | |
10 | pub(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 | 56 | pub(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 | 131 | pub(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 | } |