]> git.lizzy.rs Git - rust.git/blob - src/abi/returning.rs
[CI] Update package list before installing packages
[rust.git] / 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>,
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(_, _) => true,
48         // FIXME Make it possible to return Cast and Indirect to an ssa var.
49         PassMode::Cast(_) | PassMode::Indirect { .. } => false,
50     }
51 }
52
53 /// Return a place where the return value of the current function can be written to. If necessary
54 /// this adds an extra parameter pointing to where the return value needs to be stored.
55 pub(super) fn codegen_return_param<'tcx>(
56     fx: &mut FunctionCx<'_, '_, 'tcx>,
57     ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>,
58     block_params_iter: &mut impl Iterator<Item = Value>,
59 ) -> CPlace<'tcx> {
60     let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
61         PassMode::Ignore => (CPlace::no_place(fx.fn_abi.as_ref().unwrap().ret.layout), smallvec![]),
62         PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => {
63             let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
64             (
65                 super::make_local_place(
66                     fx,
67                     RETURN_PLACE,
68                     fx.fn_abi.as_ref().unwrap().ret.layout,
69                     is_ssa,
70                 ),
71                 smallvec![],
72             )
73         }
74         PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
75             let ret_param = block_params_iter.next().unwrap();
76             assert_eq!(fx.bcx.func.dfg.value_type(ret_param), pointer_ty(fx.tcx));
77             (
78                 CPlace::for_ptr(Pointer::new(ret_param), fx.fn_abi.as_ref().unwrap().ret.layout),
79                 smallvec![ret_param],
80             )
81         }
82         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
83             unreachable!("unsized return value")
84         }
85     };
86
87     crate::abi::comments::add_arg_comment(
88         fx,
89         "ret",
90         Some(RETURN_PLACE),
91         None,
92         &ret_param,
93         fx.fn_abi.as_ref().unwrap().ret.mode,
94         fx.fn_abi.as_ref().unwrap().ret.layout,
95     );
96
97     ret_place
98 }
99
100 /// Invokes the closure with if necessary a value representing the return pointer. When the closure
101 /// returns the call return value(s) if any are written to the correct place.
102 pub(super) fn codegen_with_call_return_arg<'tcx, T>(
103     fx: &mut FunctionCx<'_, '_, 'tcx>,
104     ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
105     ret_place: Option<CPlace<'tcx>>,
106     f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> (Inst, T),
107 ) -> (Inst, T) {
108     let return_ptr = match ret_arg_abi.mode {
109         PassMode::Ignore => None,
110         PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => match ret_place {
111             Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)),
112             None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot
113         },
114         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
115             unreachable!("unsized return value")
116         }
117         PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None,
118     };
119
120     let (call_inst, meta) = f(fx, return_ptr);
121
122     match ret_arg_abi.mode {
123         PassMode::Ignore => {}
124         PassMode::Direct(_) => {
125             if let Some(ret_place) = ret_place {
126                 let ret_val = fx.bcx.inst_results(call_inst)[0];
127                 ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout));
128             }
129         }
130         PassMode::Pair(_, _) => {
131             if let Some(ret_place) = ret_place {
132                 let ret_val_a = fx.bcx.inst_results(call_inst)[0];
133                 let ret_val_b = fx.bcx.inst_results(call_inst)[1];
134                 ret_place.write_cvalue(
135                     fx,
136                     CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout),
137                 );
138             }
139         }
140         PassMode::Cast(cast) => {
141             if let Some(ret_place) = ret_place {
142                 let results = fx
143                     .bcx
144                     .inst_results(call_inst)
145                     .iter()
146                     .copied()
147                     .collect::<SmallVec<[Value; 2]>>();
148                 let result =
149                     super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
150                 ret_place.write_cvalue(fx, result);
151             }
152         }
153         PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {}
154         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
155             unreachable!("unsized return value")
156         }
157     }
158
159     (call_inst, meta)
160 }
161
162 /// Codegen a return instruction with the right return value(s) if any.
163 pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
164     match fx.fn_abi.as_ref().unwrap().ret.mode {
165         PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
166             fx.bcx.ins().return_(&[]);
167         }
168         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
169             unreachable!("unsized return value")
170         }
171         PassMode::Direct(_) => {
172             let place = fx.get_local_place(RETURN_PLACE);
173             let ret_val = place.to_cvalue(fx).load_scalar(fx);
174             fx.bcx.ins().return_(&[ret_val]);
175         }
176         PassMode::Pair(_, _) => {
177             let place = fx.get_local_place(RETURN_PLACE);
178             let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
179             fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
180         }
181         PassMode::Cast(cast) => {
182             let place = fx.get_local_place(RETURN_PLACE);
183             let ret_val = place.to_cvalue(fx);
184             let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
185             fx.bcx.ins().return_(&ret_vals);
186         }
187     }
188 }