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