]> git.lizzy.rs Git - rust.git/blob - src/abi/returning.rs
Use the new cranelift-module interface
[rust.git] / src / abi / returning.rs
1 //! Return value handling
2
3 use crate::abi::pass_mode::*;
4 use crate::prelude::*;
5
6 fn return_layout<'a, 'tcx>(fx: &mut FunctionCx<'a, 'tcx, impl Module>) -> TyAndLayout<'tcx> {
7     fx.layout_of(fx.monomorphize(&fx.mir.local_decls[RETURN_PLACE].ty))
8 }
9
10 /// Can the given type be returned into an ssa var or does it need to be returned on the stack.
11 pub(crate) fn can_return_to_ssa_var<'tcx>(
12     tcx: TyCtxt<'tcx>,
13     dest_layout: TyAndLayout<'tcx>,
14 ) -> bool {
15     match get_pass_mode(tcx, dest_layout) {
16         PassMode::NoPass | PassMode::ByVal(_) | PassMode::ByValPair(_, _) => true,
17         // FIXME Make it possible to return ByRef to an ssa var.
18         PassMode::ByRef { size: _ } => false,
19     }
20 }
21
22 /// Return a place where the return value of the current function can be written to. If necessary
23 /// this adds an extra parameter pointing to where the return value needs to be stored.
24 pub(super) fn codegen_return_param<'tcx>(
25     fx: &mut FunctionCx<'_, 'tcx, impl Module>,
26     ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>,
27     start_block: Block,
28 ) -> CPlace<'tcx> {
29     let ret_layout = return_layout(fx);
30     let ret_pass_mode = get_pass_mode(fx.tcx, ret_layout);
31     let (ret_place, ret_param) = match ret_pass_mode {
32         PassMode::NoPass => (CPlace::no_place(ret_layout), Empty),
33         PassMode::ByVal(_) | PassMode::ByValPair(_, _) => {
34             let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
35             (
36                 super::make_local_place(fx, RETURN_PLACE, ret_layout, is_ssa),
37                 Empty,
38             )
39         }
40         PassMode::ByRef { size: Some(_) } => {
41             let ret_param = fx.bcx.append_block_param(start_block, fx.pointer_type);
42             (
43                 CPlace::for_ptr(Pointer::new(ret_param), ret_layout),
44                 Single(ret_param),
45             )
46         }
47         PassMode::ByRef { size: None } => todo!(),
48     };
49
50     #[cfg(not(debug_assertions))]
51     let _ = ret_param;
52
53     #[cfg(debug_assertions)]
54     crate::abi::comments::add_arg_comment(
55         fx,
56         "ret",
57         Some(RETURN_PLACE),
58         None,
59         ret_param,
60         ret_pass_mode,
61         ret_layout.ty,
62     );
63
64     ret_place
65 }
66
67 /// Invokes the closure with if necessary a value representing the return pointer. When the closure
68 /// returns the call return value(s) if any are written to the correct place.
69 pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>(
70     fx: &mut FunctionCx<'_, 'tcx, M>,
71     fn_sig: FnSig<'tcx>,
72     ret_place: Option<CPlace<'tcx>>,
73     f: impl FnOnce(&mut FunctionCx<'_, 'tcx, M>, Option<Value>) -> (Inst, T),
74 ) -> (Inst, T) {
75     let ret_layout = fx.layout_of(fn_sig.output());
76
77     let output_pass_mode = get_pass_mode(fx.tcx, ret_layout);
78     let return_ptr = match output_pass_mode {
79         PassMode::NoPass => None,
80         PassMode::ByRef { size: Some(_) } => match ret_place {
81             Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)),
82             None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot
83         },
84         PassMode::ByRef { size: None } => todo!(),
85         PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None,
86     };
87
88     let (call_inst, meta) = f(fx, return_ptr);
89
90     match output_pass_mode {
91         PassMode::NoPass => {}
92         PassMode::ByVal(_) => {
93             if let Some(ret_place) = ret_place {
94                 let ret_val = fx.bcx.inst_results(call_inst)[0];
95                 ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_layout));
96             }
97         }
98         PassMode::ByValPair(_, _) => {
99             if let Some(ret_place) = ret_place {
100                 let ret_val_a = fx.bcx.inst_results(call_inst)[0];
101                 let ret_val_b = fx.bcx.inst_results(call_inst)[1];
102                 ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout));
103             }
104         }
105         PassMode::ByRef { size: Some(_) } => {}
106         PassMode::ByRef { size: None } => todo!(),
107     }
108
109     (call_inst, meta)
110 }
111
112 /// Codegen a return instruction with the right return value(s) if any.
113 pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, impl Module>) {
114     match get_pass_mode(fx.tcx, return_layout(fx)) {
115         PassMode::NoPass | PassMode::ByRef { size: Some(_) } => {
116             fx.bcx.ins().return_(&[]);
117         }
118         PassMode::ByRef { size: None } => todo!(),
119         PassMode::ByVal(_) => {
120             let place = fx.get_local_place(RETURN_PLACE);
121             let ret_val = place.to_cvalue(fx).load_scalar(fx);
122             fx.bcx.ins().return_(&[ret_val]);
123         }
124         PassMode::ByValPair(_, _) => {
125             let place = fx.get_local_place(RETURN_PLACE);
126             let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
127             fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
128         }
129     }
130 }