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