about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2019-08-30 15:41:33 +0200
committerbjorn3 <bjorn3@users.noreply.github.com>2019-08-30 15:42:07 +0200
commit15b9834d7d37d601fd77db11f8852f9ceb0804d0 (patch)
tree88cbecfbdd562beb49c4ea8f8fb978b2d97d5eb9
parent76d2e085db71370cb34fc12fc544f46e557e743d (diff)
downloadrust-15b9834d7d37d601fd77db11f8852f9ceb0804d0.tar.gz
rust-15b9834d7d37d601fd77db11f8852f9ceb0804d0.zip
Don't copy ByRef passed types to local stack slot when not necessary
Eg when the local is immutable **and** the type is freeze.

This makes the simple raytracer runtime benchmark 1% faster than cg_llvm
without optimizations. Before it was 2% slower.

cc #691
cc #684
-rw-r--r--example/example.rs4
-rw-r--r--src/abi/comments.rs11
-rw-r--r--src/abi/mod.rs28
-rw-r--r--src/value_and_place.rs7
4 files changed, 49 insertions, 1 deletions
diff --git a/example/example.rs b/example/example.rs
index e8ddc4aaea1..5878e8548d9 100644
--- a/example/example.rs
+++ b/example/example.rs
@@ -202,3 +202,7 @@ fn get_sized_field_ref_from_unsized_type(u: &Unsized) -> &u8 {
 fn get_unsized_field_ref_from_unsized_type(u: &Unsized) -> &str {
     &u.1
 }
+
+pub fn reuse_byref_argument_storage(a: (u8, u16, u32)) -> u8 {
+    a.0
+}
diff --git a/src/abi/comments.rs b/src/abi/comments.rs
index b7932e2ba58..77649e40b19 100644
--- a/src/abi/comments.rs
+++ b/src/abi/comments.rs
@@ -94,6 +94,15 @@ pub fn add_local_place_comments<'tcx>(
             align.abi.bytes(),
             align.pref.bytes(),
         )),
-        CPlaceInner::Addr(_, _) => unreachable!(),
+        CPlaceInner::Addr(addr, None) => fx.add_global_comment(format!(
+            "reuse {:5} {:20} {:4}b {}, {}              storage={}",
+            format!("{:?}", local),
+            format!("{:?}", ty),
+            size.bytes(),
+            align.abi.bytes(),
+            align.pref.bytes(),
+            addr,
+        )),
+        CPlaceInner::Addr(_, Some(_)) => unreachable!(),
     }
 }
diff --git a/src/abi/mod.rs b/src/abi/mod.rs
index eaf25ef48ec..45277694702 100644
--- a/src/abi/mod.rs
+++ b/src/abi/mod.rs
@@ -282,6 +282,34 @@ pub fn codegen_fn_prelude(
             .unwrap()
             .contains(crate::analyze::Flags::NOT_SSA);
 
+        match arg_kind {
+            ArgKind::Normal(Some(val)) => {
+                if let Some(addr) = val.try_to_addr() {
+                    let local_decl = &fx.mir.local_decls[local];
+                    //                             v this ! is important
+                    let internally_mutable = !val.layout().ty.is_freeze(
+                        fx.tcx,
+                        ParamEnv::reveal_all(),
+                        local_decl.source_info.span,
+                    );
+                    if local_decl.mutability == mir::Mutability::Not && internally_mutable {
+                        // We wont mutate this argument, so it is fine to borrow the backing storage
+                        // of this argument, to prevent a copy.
+
+                        let place = CPlace::for_addr(addr, val.layout());
+
+                        #[cfg(debug_assertions)]
+                        self::comments::add_local_place_comments(fx, place, local);
+
+                        let prev_place = fx.local_map.insert(local, place);
+                        debug_assert!(prev_place.is_none());
+                        continue;
+                    }
+                }
+            }
+            _ => {}
+        }
+
         let place = local_place(fx, local, layout, is_ssa);
 
         match arg_kind {
diff --git a/src/value_and_place.rs b/src/value_and_place.rs
index b300db2ecfc..b1da6e2b4ea 100644
--- a/src/value_and_place.rs
+++ b/src/value_and_place.rs
@@ -63,6 +63,13 @@ impl<'tcx> CValue<'tcx> {
         }
     }
 
+    pub fn try_to_addr(self) -> Option<Value> {
+        match self.0 {
+            CValueInner::ByRef(addr) => Some(addr),
+            CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => None,
+        }
+    }
+
     /// Load a value with layout.abi of scalar
     pub fn load_scalar<'a>(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> Value {
         let layout = self.1;