]> git.lizzy.rs Git - rust.git/blob - src/abi/returning.rs
Move return handling to abi/returning.rs
[rust.git] / src / abi / returning.rs
1 use crate::prelude::*;
2 use crate::abi::pass_mode::*;
3
4 pub fn codegen_return_param(
5     fx: &mut FunctionCx<impl Backend>,
6     ssa_analyzed: &HashMap<Local, crate::analyze::Flags>,
7     start_ebb: Ebb,
8 ) {
9     let ret_layout = fx.return_layout();
10     let output_pass_mode = get_pass_mode(fx.tcx, fx.return_layout());
11
12     let ret_param = match output_pass_mode {
13         PassMode::NoPass => {
14             fx.local_map
15                 .insert(RETURN_PLACE, CPlace::no_place(ret_layout));
16             Empty
17         }
18         PassMode::ByVal(_) | PassMode::ByValPair(_, _) => {
19             let is_ssa = !ssa_analyzed
20                 .get(&RETURN_PLACE)
21                 .unwrap()
22                 .contains(crate::analyze::Flags::NOT_SSA);
23
24             super::local_place(fx, RETURN_PLACE, ret_layout, is_ssa);
25
26             Empty
27         }
28         PassMode::ByRef => {
29             let ret_param = fx.bcx.append_ebb_param(start_ebb, fx.pointer_type);
30             fx.local_map.insert(
31                 RETURN_PLACE,
32                 CPlace::for_addr(ret_param, ret_layout),
33             );
34
35             Single(ret_param)
36         }
37     };
38
39     #[cfg(debug_assertions)]
40     {
41         super::add_arg_comment(
42             fx,
43             "ret",
44             RETURN_PLACE,
45             None,
46             ret_param,
47             output_pass_mode,
48             ssa_analyzed[&RETURN_PLACE],
49             ret_layout.ty,
50         );
51     }
52 }
53
54 pub fn codegen_with_call_return_arg<'tcx, B: Backend, T>(
55     fx: &mut FunctionCx<'_, 'tcx, B>,
56     fn_sig: FnSig<'tcx>,
57     ret_place: Option<CPlace<'tcx>>,
58     f: impl FnOnce(&mut FunctionCx<'_, 'tcx, B>, Option<Value>) -> (Inst, T),
59 ) -> (Inst, T) {
60     let ret_layout = fx.layout_of(fn_sig.output());
61
62     let output_pass_mode = get_pass_mode(fx.tcx, ret_layout);
63     let return_ptr = match output_pass_mode {
64         PassMode::NoPass => None,
65         PassMode::ByRef => match ret_place {
66             Some(ret_place) => Some(ret_place.to_addr(fx)),
67             None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)),
68         },
69         PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None,
70     };
71
72     let (call_inst, meta) = f(fx, return_ptr);
73
74     match output_pass_mode {
75         PassMode::NoPass => {}
76         PassMode::ByVal(_) => {
77             if let Some(ret_place) = ret_place {
78                 let ret_val = fx.bcx.inst_results(call_inst)[0];
79                 ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_layout));
80             }
81         }
82         PassMode::ByValPair(_, _) => {
83             if let Some(ret_place) = ret_place {
84                 let ret_val_a = fx.bcx.inst_results(call_inst)[0];
85                 let ret_val_b = fx.bcx.inst_results(call_inst)[1];
86                 ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout));
87             }
88         }
89         PassMode::ByRef => {}
90     }
91
92     (call_inst, meta)
93 }
94
95 pub fn codegen_return(fx: &mut FunctionCx<impl Backend>) {
96     match get_pass_mode(fx.tcx, fx.return_layout()) {
97         PassMode::NoPass | PassMode::ByRef => {
98             fx.bcx.ins().return_(&[]);
99         }
100         PassMode::ByVal(_) => {
101             let place = fx.get_local_place(RETURN_PLACE);
102             let ret_val = place.to_cvalue(fx).load_scalar(fx);
103             fx.bcx.ins().return_(&[ret_val]);
104         }
105         PassMode::ByValPair(_, _) => {
106             let place = fx.get_local_place(RETURN_PLACE);
107             let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
108             fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
109         }
110     }
111 }