]> git.lizzy.rs Git - rust.git/blob - src/abi/returning.rs
Enable inline asm on macOS
[rust.git] / src / abi / returning.rs
1 //! Return value handling
2
3 use crate::prelude::*;
4
5 use rustc_target::abi::call::{ArgAbi, PassMode};
6 use smallvec::{smallvec, SmallVec};
7
8 /// Return a place where the return value of the current function can be written to. If necessary
9 /// this adds an extra parameter pointing to where the return value needs to be stored.
10 pub(super) fn codegen_return_param<'tcx>(
11     fx: &mut FunctionCx<'_, '_, 'tcx>,
12     ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>,
13     block_params_iter: &mut impl Iterator<Item = Value>,
14 ) -> CPlace<'tcx> {
15     let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
16         PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => {
17             let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
18             (
19                 super::make_local_place(
20                     fx,
21                     RETURN_PLACE,
22                     fx.fn_abi.as_ref().unwrap().ret.layout,
23                     is_ssa,
24                 ),
25                 smallvec![],
26             )
27         }
28         PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
29             let ret_param = block_params_iter.next().unwrap();
30             assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type);
31             (
32                 CPlace::for_ptr(Pointer::new(ret_param), fx.fn_abi.as_ref().unwrap().ret.layout),
33                 smallvec![ret_param],
34             )
35         }
36         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
37             unreachable!("unsized return value")
38         }
39     };
40
41     crate::abi::comments::add_arg_comment(
42         fx,
43         "ret",
44         Some(RETURN_PLACE),
45         None,
46         &ret_param,
47         fx.fn_abi.as_ref().unwrap().ret.mode,
48         fx.fn_abi.as_ref().unwrap().ret.layout,
49     );
50
51     ret_place
52 }
53
54 /// Invokes the closure with if necessary a value representing the return pointer. When the closure
55 /// returns the call return value(s) if any are written to the correct place.
56 pub(super) fn codegen_with_call_return_arg<'tcx>(
57     fx: &mut FunctionCx<'_, '_, 'tcx>,
58     ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
59     ret_place: CPlace<'tcx>,
60     f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> Inst,
61 ) {
62     let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
63         PassMode::Ignore => (None, None),
64         PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
65             if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) {
66                 // This is an optimization to prevent unnecessary copies of the return value when
67                 // the return place is already a memory place as opposed to a register.
68                 // This match arm can be safely removed.
69                 (None, Some(ret_place.to_ptr().get_addr(fx)))
70             } else {
71                 let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout);
72                 (Some(place), Some(place.to_ptr().get_addr(fx)))
73             }
74         }
75         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
76             unreachable!("unsized return value")
77         }
78         PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => (None, None),
79     };
80
81     let call_inst = f(fx, return_ptr);
82
83     match ret_arg_abi.mode {
84         PassMode::Ignore => {}
85         PassMode::Direct(_) => {
86             let ret_val = fx.bcx.inst_results(call_inst)[0];
87             ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout));
88         }
89         PassMode::Pair(_, _) => {
90             let ret_val_a = fx.bcx.inst_results(call_inst)[0];
91             let ret_val_b = fx.bcx.inst_results(call_inst)[1];
92             ret_place
93                 .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout));
94         }
95         PassMode::Cast(cast) => {
96             let results =
97                 fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>();
98             let result =
99                 super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
100             ret_place.write_cvalue(fx, result);
101         }
102         PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
103             if let Some(ret_temp_place) = ret_temp_place {
104                 // If ret_temp_place is None, it is not necessary to copy the return value.
105                 let ret_temp_value = ret_temp_place.to_cvalue(fx);
106                 ret_place.write_cvalue(fx, ret_temp_value);
107             }
108         }
109         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
110             unreachable!("unsized return value")
111         }
112     }
113 }
114
115 /// Codegen a return instruction with the right return value(s) if any.
116 pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
117     match fx.fn_abi.as_ref().unwrap().ret.mode {
118         PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
119             fx.bcx.ins().return_(&[]);
120         }
121         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
122             unreachable!("unsized return value")
123         }
124         PassMode::Direct(_) => {
125             let place = fx.get_local_place(RETURN_PLACE);
126             let ret_val = place.to_cvalue(fx).load_scalar(fx);
127             fx.bcx.ins().return_(&[ret_val]);
128         }
129         PassMode::Pair(_, _) => {
130             let place = fx.get_local_place(RETURN_PLACE);
131             let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
132             fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
133         }
134         PassMode::Cast(cast) => {
135             let place = fx.get_local_place(RETURN_PLACE);
136             let ret_val = place.to_cvalue(fx);
137             let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
138             fx.bcx.ins().return_(&ret_vals);
139         }
140     }
141 }