]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/abi/returning.rs
Auto merge of #81361 - ssomers:btree_drainy_refactor_7, r=Mark-Simulacrum
[rust.git] / compiler / rustc_codegen_cranelift / src / abi / returning.rs
1 //! Return value handling
2
3 use crate::prelude::*;
4
5 use rustc_middle::ty::layout::FnAbiExt;
6 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
7 use smallvec::{smallvec, SmallVec};
8
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>],
14 ) -> bool {
15     let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
16     let fn_sig = fx
17         .tcx
18         .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
19
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)
23             .unwrap()
24             .unwrap()
25             .polymorphize(fx.tcx);
26
27         match instance.def {
28             InstanceDef::Intrinsic(_) | InstanceDef::DropGlue(_, _) => {
29                 return true;
30             }
31             _ => Some(instance),
32         }
33     } else {
34         None
35     };
36
37     let extra_args = &args[fn_sig.inputs().len()..];
38     let extra_args = extra_args
39         .iter()
40         .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))
41         .collect::<Vec<_>>();
42     let fn_abi = if let Some(instance) = instance {
43         FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args)
44     } else {
45         FnAbi::of_fn_ptr(
46             &RevealAllLayoutCx(fx.tcx),
47             fn_ty.fn_sig(fx.tcx),
48             &extra_args,
49         )
50     };
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,
55     }
56 }
57
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>,
64 ) -> CPlace<'tcx> {
65     let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
66         PassMode::Ignore => (
67             CPlace::no_place(fx.fn_abi.as_ref().unwrap().ret.layout),
68             smallvec![],
69         ),
70         PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => {
71             let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
72             (
73                 super::make_local_place(
74                     fx,
75                     RETURN_PLACE,
76                     fx.fn_abi.as_ref().unwrap().ret.layout,
77                     is_ssa,
78                 ),
79                 smallvec![],
80             )
81         }
82         PassMode::Indirect {
83             attrs: _,
84             extra_attrs: None,
85             on_stack: _,
86         } => {
87             let ret_param = block_params_iter.next().unwrap();
88             assert_eq!(fx.bcx.func.dfg.value_type(ret_param), pointer_ty(fx.tcx));
89             (
90                 CPlace::for_ptr(
91                     Pointer::new(ret_param),
92                     fx.fn_abi.as_ref().unwrap().ret.layout,
93                 ),
94                 smallvec![ret_param],
95             )
96         }
97         PassMode::Indirect {
98             attrs: _,
99             extra_attrs: Some(_),
100             on_stack: _,
101         } => unreachable!("unsized return value"),
102     };
103
104     #[cfg(not(debug_assertions))]
105     let _ = ret_param;
106
107     #[cfg(debug_assertions)]
108     crate::abi::comments::add_arg_comment(
109         fx,
110         "ret",
111         Some(RETURN_PLACE),
112         None,
113         &ret_param,
114         fx.fn_abi.as_ref().unwrap().ret.mode,
115         fx.fn_abi.as_ref().unwrap().ret.layout,
116     );
117
118     ret_place
119 }
120
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),
128 ) -> (Inst, T) {
129     let return_ptr = match ret_arg_abi.mode {
130         PassMode::Ignore => None,
131         PassMode::Indirect {
132             attrs: _,
133             extra_attrs: None,
134             on_stack: _,
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
138         },
139         PassMode::Indirect {
140             attrs: _,
141             extra_attrs: Some(_),
142             on_stack: _,
143         } => unreachable!("unsized return value"),
144         PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None,
145     };
146
147     let (call_inst, meta) = f(fx, return_ptr);
148
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));
155             }
156         }
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(
162                     fx,
163                     CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout),
164                 );
165             }
166         }
167         PassMode::Cast(cast) => {
168             if let Some(ret_place) = ret_place {
169                 let results = fx
170                     .bcx
171                     .inst_results(call_inst)
172                     .into_iter()
173                     .copied()
174                     .collect::<SmallVec<[Value; 2]>>();
175                 let result =
176                     super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
177                 ret_place.write_cvalue(fx, result);
178             }
179         }
180         PassMode::Indirect {
181             attrs: _,
182             extra_attrs: None,
183             on_stack: _,
184         } => {}
185         PassMode::Indirect {
186             attrs: _,
187             extra_attrs: Some(_),
188             on_stack: _,
189         } => unreachable!("unsized return value"),
190     }
191
192     (call_inst, meta)
193 }
194
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 {
198         PassMode::Ignore
199         | PassMode::Indirect {
200             attrs: _,
201             extra_attrs: None,
202             on_stack: _,
203         } => {
204             fx.bcx.ins().return_(&[]);
205         }
206         PassMode::Indirect {
207             attrs: _,
208             extra_attrs: Some(_),
209             on_stack: _,
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]);
215         }
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]);
220         }
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);
226         }
227     }
228 }