]> git.lizzy.rs Git - rust.git/blobdiff - src/abi/returning.rs
[CI] Update package list before installing packages
[rust.git] / src / abi / returning.rs
index 45ba48d7c4f99d340dd139065e79075bc3db9749..e1c53224b4f841751bba96f80a37b99fbcdd9e93 100644 (file)
+//! Return value handling
+
 use crate::prelude::*;
-use crate::abi::pass_mode::*;
 
-pub fn codegen_return_param(
-    fx: &mut FunctionCx<impl Backend>,
-    ssa_analyzed: &HashMap<Local, crate::analyze::Flags>,
-    start_ebb: Ebb,
-) {
-    let ret_layout = fx.return_layout();
-    let output_pass_mode = get_pass_mode(fx.tcx, fx.return_layout());
+use rustc_middle::ty::layout::FnAbiExt;
+use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use smallvec::{smallvec, SmallVec};
 
-    let ret_param = match output_pass_mode {
-        PassMode::NoPass => {
-            fx.local_map
-                .insert(RETURN_PLACE, CPlace::no_place(ret_layout));
-            Empty
-        }
-        PassMode::ByVal(_) | PassMode::ByValPair(_, _) => {
-            let is_ssa = !ssa_analyzed
-                .get(&RETURN_PLACE)
-                .unwrap()
-                .contains(crate::analyze::Flags::NOT_SSA);
+/// Can the given type be returned into an ssa var or does it need to be returned on the stack.
+pub(crate) fn can_return_to_ssa_var<'tcx>(
+    fx: &FunctionCx<'_, '_, 'tcx>,
+    func: &mir::Operand<'tcx>,
+    args: &[mir::Operand<'tcx>],
+) -> bool {
+    let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
+    let fn_sig =
+        fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
 
-            super::local_place(fx, RETURN_PLACE, ret_layout, is_ssa);
+    // Handle special calls like instrinsics and empty drop glue.
+    let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
+        let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
+            .unwrap()
+            .unwrap()
+            .polymorphize(fx.tcx);
 
-            Empty
+        match instance.def {
+            InstanceDef::Intrinsic(_) | InstanceDef::DropGlue(_, _) => {
+                return true;
+            }
+            _ => Some(instance),
         }
-        PassMode::ByRef => {
-            let ret_param = fx.bcx.append_ebb_param(start_ebb, fx.pointer_type);
-            fx.local_map.insert(
-                RETURN_PLACE,
-                CPlace::for_addr(ret_param, ret_layout),
-            );
+    } else {
+        None
+    };
 
-            Single(ret_param)
+    let extra_args = &args[fn_sig.inputs().len()..];
+    let extra_args = extra_args
+        .iter()
+        .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))
+        .collect::<Vec<_>>();
+    let fn_abi = if let Some(instance) = instance {
+        FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args)
+    } else {
+        FnAbi::of_fn_ptr(&RevealAllLayoutCx(fx.tcx), fn_ty.fn_sig(fx.tcx), &extra_args)
+    };
+    match fn_abi.ret.mode {
+        PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) => true,
+        // FIXME Make it possible to return Cast and Indirect to an ssa var.
+        PassMode::Cast(_) | PassMode::Indirect { .. } => false,
+    }
+}
+
+/// Return a place where the return value of the current function can be written to. If necessary
+/// this adds an extra parameter pointing to where the return value needs to be stored.
+pub(super) fn codegen_return_param<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>,
+    block_params_iter: &mut impl Iterator<Item = Value>,
+) -> CPlace<'tcx> {
+    let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
+        PassMode::Ignore => (CPlace::no_place(fx.fn_abi.as_ref().unwrap().ret.layout), smallvec![]),
+        PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => {
+            let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
+            (
+                super::make_local_place(
+                    fx,
+                    RETURN_PLACE,
+                    fx.fn_abi.as_ref().unwrap().ret.layout,
+                    is_ssa,
+                ),
+                smallvec![],
+            )
+        }
+        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+            let ret_param = block_params_iter.next().unwrap();
+            assert_eq!(fx.bcx.func.dfg.value_type(ret_param), pointer_ty(fx.tcx));
+            (
+                CPlace::for_ptr(Pointer::new(ret_param), fx.fn_abi.as_ref().unwrap().ret.layout),
+                smallvec![ret_param],
+            )
+        }
+        PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+            unreachable!("unsized return value")
         }
     };
 
-    #[cfg(debug_assertions)]
-    {
-        super::add_arg_comment(
-            fx,
-            "ret",
-            RETURN_PLACE,
-            None,
-            ret_param,
-            output_pass_mode,
-            ssa_analyzed[&RETURN_PLACE],
-            ret_layout.ty,
-        );
-    }
+    crate::abi::comments::add_arg_comment(
+        fx,
+        "ret",
+        Some(RETURN_PLACE),
+        None,
+        &ret_param,
+        fx.fn_abi.as_ref().unwrap().ret.mode,
+        fx.fn_abi.as_ref().unwrap().ret.layout,
+    );
+
+    ret_place
 }
 
-pub fn codegen_with_call_return_arg<'tcx, B: Backend, T>(
-    fx: &mut FunctionCx<'_, 'tcx, B>,
-    fn_sig: FnSig<'tcx>,
+/// Invokes the closure with if necessary a value representing the return pointer. When the closure
+/// returns the call return value(s) if any are written to the correct place.
+pub(super) fn codegen_with_call_return_arg<'tcx, T>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
     ret_place: Option<CPlace<'tcx>>,
-    f: impl FnOnce(&mut FunctionCx<'_, 'tcx, B>, Option<Value>) -> (Inst, T),
+    f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> (Inst, T),
 ) -> (Inst, T) {
-    let ret_layout = fx.layout_of(fn_sig.output());
-
-    let output_pass_mode = get_pass_mode(fx.tcx, ret_layout);
-    let return_ptr = match output_pass_mode {
-        PassMode::NoPass => None,
-        PassMode::ByRef => match ret_place {
-            Some(ret_place) => Some(ret_place.to_addr(fx)),
-            None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)),
+    let return_ptr = match ret_arg_abi.mode {
+        PassMode::Ignore => None,
+        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => match ret_place {
+            Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)),
+            None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot
         },
-        PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None,
+        PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+            unreachable!("unsized return value")
+        }
+        PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None,
     };
 
     let (call_inst, meta) = f(fx, return_ptr);
 
-    match output_pass_mode {
-        PassMode::NoPass => {}
-        PassMode::ByVal(_) => {
+    match ret_arg_abi.mode {
+        PassMode::Ignore => {}
+        PassMode::Direct(_) => {
             if let Some(ret_place) = ret_place {
                 let ret_val = fx.bcx.inst_results(call_inst)[0];
-                ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_layout));
+                ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout));
             }
         }
-        PassMode::ByValPair(_, _) => {
+        PassMode::Pair(_, _) => {
             if let Some(ret_place) = ret_place {
                 let ret_val_a = fx.bcx.inst_results(call_inst)[0];
                 let ret_val_b = fx.bcx.inst_results(call_inst)[1];
-                ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout));
+                ret_place.write_cvalue(
+                    fx,
+                    CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout),
+                );
+            }
+        }
+        PassMode::Cast(cast) => {
+            if let Some(ret_place) = ret_place {
+                let results = fx
+                    .bcx
+                    .inst_results(call_inst)
+                    .iter()
+                    .copied()
+                    .collect::<SmallVec<[Value; 2]>>();
+                let result =
+                    super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
+                ret_place.write_cvalue(fx, result);
             }
         }
-        PassMode::ByRef => {}
+        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {}
+        PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+            unreachable!("unsized return value")
+        }
     }
 
     (call_inst, meta)
 }
 
-pub fn codegen_return(fx: &mut FunctionCx<impl Backend>) {
-    match get_pass_mode(fx.tcx, fx.return_layout()) {
-        PassMode::NoPass | PassMode::ByRef => {
+/// Codegen a return instruction with the right return value(s) if any.
+pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
+    match fx.fn_abi.as_ref().unwrap().ret.mode {
+        PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
             fx.bcx.ins().return_(&[]);
         }
-        PassMode::ByVal(_) => {
+        PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+            unreachable!("unsized return value")
+        }
+        PassMode::Direct(_) => {
             let place = fx.get_local_place(RETURN_PLACE);
             let ret_val = place.to_cvalue(fx).load_scalar(fx);
             fx.bcx.ins().return_(&[ret_val]);
         }
-        PassMode::ByValPair(_, _) => {
+        PassMode::Pair(_, _) => {
             let place = fx.get_local_place(RETURN_PLACE);
             let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
             fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
         }
+        PassMode::Cast(cast) => {
+            let place = fx.get_local_place(RETURN_PLACE);
+            let ret_val = place.to_cvalue(fx);
+            let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
+            fx.bcx.ins().return_(&ret_vals);
+        }
     }
 }