about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2021-07-28 18:54:21 +0200
committerbjorn3 <bjorn3@users.noreply.github.com>2021-07-28 18:54:21 +0200
commite0b9f3b3cc3cdf3edcf0868e6c88e652455055fd (patch)
treec74d763198985712954cc23fc8e65fadccdc64e7
parentb7881bb08d129a119c69ca79999cae54cef3efb4 (diff)
downloadrust-e0b9f3b3cc3cdf3edcf0868e6c88e652455055fd.tar.gz
rust-e0b9f3b3cc3cdf3edcf0868e6c88e652455055fd.zip
Support storing return values in register places for all pass modes
-rw-r--r--src/abi/mod.rs2
-rw-r--r--src/abi/returning.rs75
-rw-r--r--src/analyze.rs11
3 files changed, 24 insertions, 64 deletions
diff --git a/src/abi/mod.rs b/src/abi/mod.rs
index 0478d4b198a..13790409e59 100644
--- a/src/abi/mod.rs
+++ b/src/abi/mod.rs
@@ -14,7 +14,7 @@ use cranelift_codegen::ir::{AbiParam, SigRef};
 use self::pass_mode::*;
 use crate::prelude::*;
 
-pub(crate) use self::returning::{can_return_to_ssa_var, codegen_return};
+pub(crate) use self::returning::codegen_return;
 
 fn clif_sig_from_fn_abi<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/src/abi/returning.rs b/src/abi/returning.rs
index f9fc3992ae2..c1bdba43e6c 100644
--- a/src/abi/returning.rs
+++ b/src/abi/returning.rs
@@ -2,54 +2,9 @@
 
 use crate::prelude::*;
 
-use rustc_middle::ty::layout::FnAbiExt;
-use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_target::abi::call::{ArgAbi, PassMode};
 use smallvec::{smallvec, SmallVec};
 
-/// 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));
-
-    // 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);
-
-        match instance.def {
-            InstanceDef::Intrinsic(_) | InstanceDef::DropGlue(_, _) => {
-                return true;
-            }
-            _ => Some(instance),
-        }
-    } else {
-        None
-    };
-
-    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(_, _) | PassMode::Cast(_) => true,
-        // FIXME Make it possible to return Indirect to an ssa var.
-        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>(
@@ -104,16 +59,24 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
     ret_place: Option<CPlace<'tcx>>,
     f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> Inst,
 ) {
-    let return_ptr = match ret_arg_abi.mode {
-        PassMode::Ignore => None,
+    let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
+        PassMode::Ignore => (None, 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
+            Some(ret_place) if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) => {
+                // This is an optimization to prevent unnecessary copies of the return value when
+                // the return place is already a memory place as opposed to a register.
+                // This match arm can be safely removed.
+                (None, Some(ret_place.to_ptr().get_addr(fx)))
+            }
+            _ => {
+                let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout);
+                (Some(place), Some(place.to_ptr().get_addr(fx)))
+            }
         },
         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
             unreachable!("unsized return value")
         }
-        PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None,
+        PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => (None, None),
     };
 
     let call_inst = f(fx, return_ptr);
@@ -149,7 +112,15 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
                 ret_place.write_cvalue(fx, result);
             }
         }
-        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {}
+        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+            if let (Some(ret_place), Some(ret_temp_place)) = (ret_place, ret_temp_place) {
+                // Both ret_place and ret_temp_place must be Some. If ret_place is None, this is
+                // a non-returning call. If ret_temp_place is None, it is not necessary to copy the
+                // return value.
+                let ret_temp_value = ret_temp_place.to_cvalue(fx);
+                ret_place.write_cvalue(fx, ret_temp_value);
+            }
+        }
         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
             unreachable!("unsized return value")
         }
diff --git a/src/analyze.rs b/src/analyze.rs
index efead25552f..35b89358b19 100644
--- a/src/analyze.rs
+++ b/src/analyze.rs
@@ -38,17 +38,6 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec<Local, SsaKind> {
                 _ => {}
             }
         }
-
-        match &bb.terminator().kind {
-            TerminatorKind::Call { destination, func, args, .. } => {
-                if let Some((dest_place, _dest_bb)) = destination {
-                    if !crate::abi::can_return_to_ssa_var(fx, func, args) {
-                        not_ssa(&mut flag_map, dest_place.local)
-                    }
-                }
-            }
-            _ => {}
-        }
     }
 
     flag_map