about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@fb.com>2022-10-26 15:12:19 -0700
committerErik Desjardins <erikdesjardins@users.noreply.github.com>2023-05-20 18:12:53 -0400
commitf71741bac41a5373791958d4a0a36c84d83b1bd5 (patch)
tree762bbc4bb5d452de51ebcb77b96cc251f6ec40dc /compiler
parente77366b57b799dfa3ce1fcb850c068723a3213ee (diff)
downloadrust-f71741bac41a5373791958d4a0a36c84d83b1bd5.tar.gz
rust-f71741bac41a5373791958d4a0a36c84d83b1bd5.zip
[rustc_ty_utils] Add the LLVM `noalias` parameter attribute to `drop_in_place` in certain cases.
LLVM can make use of the `noalias` parameter attribute on the parameter to
`drop_in_place` in areas like argument promotion. Because the Rust compiler
fully controls the code for `drop_in_place`, it can soundly deduce parameter
attributes on it. In the case of a value that has a programmer-defined Drop
implementation, we know that the first thing `drop_in_place` will do is pass a
pointer to the object to `Drop::drop`. `Drop::drop` takes `&mut`, so it must be
guaranteed that there are no pointers to the object upon entering that
function. Therefore, it should be safe to mark `noalias` there.

With this patch, we mark `noalias` only when the type is a value with a
programmer-defined Drop implementation. This is possibly overly conservative,
but I thought that proceeding cautiously was best in this instance.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs36
1 files changed, 35 insertions, 1 deletions
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 442d041a8a7..9b0d34b8979 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -238,6 +238,7 @@ fn adjust_for_rust_scalar<'tcx>(
     layout: TyAndLayout<'tcx>,
     offset: Size,
     is_return: bool,
+    is_drop_target: bool,
 ) {
     // Booleans are always a noundef i1 that needs to be zero-extended.
     if scalar.is_bool() {
@@ -307,6 +308,25 @@ fn adjust_for_rust_scalar<'tcx>(
             }
         }
     }
+
+    // If this is the argument to `drop_in_place`, the contents of which we fully control as the
+    // compiler, then we may be able to mark that argument `noalias`. Currently, we're conservative
+    // and do so only if `drop_in_place` results in a direct call to the programmer's `drop` method.
+    // The `drop` method requires `&mut self`, so we're effectively just propagating the `noalias`
+    // guarantee from `drop` upward to `drop_in_place` in this case.
+    if is_drop_target {
+        match *layout.ty.kind() {
+            ty::RawPtr(inner) => {
+                if let ty::Adt(adt_def, _) = inner.ty.kind() {
+                    if adt_def.destructor(cx.tcx()).is_some() {
+                        debug!("marking drop_in_place argument as noalias");
+                        attrs.set(ArgAttribute::NoAlias);
+                    }
+                }
+            }
+            _ => bug!("drop target isn't a raw pointer"),
+        }
+    }
 }
 
 // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
@@ -362,10 +382,16 @@ fn fn_abi_new_uncached<'tcx>(
     use SpecAbi::*;
     let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
 
+    let is_drop_in_place = match (cx.tcx.lang_items().drop_in_place_fn(), fn_def_id) {
+        (Some(drop_in_place_fn), Some(fn_def_id)) => drop_in_place_fn == fn_def_id,
+        _ => false,
+    };
+
     let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
         let span = tracing::debug_span!("arg_of");
         let _entered = span.enter();
         let is_return = arg_idx.is_none();
+        let is_drop_target = is_drop_in_place && arg_idx == Some(0);
 
         let layout = cx.layout_of(ty)?;
         let layout = if force_thin_self_ptr && arg_idx == Some(0) {
@@ -379,7 +405,15 @@ fn fn_abi_new_uncached<'tcx>(
 
         let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| {
             let mut attrs = ArgAttributes::new();
-            adjust_for_rust_scalar(*cx, &mut attrs, scalar, *layout, offset, is_return);
+            adjust_for_rust_scalar(
+                *cx,
+                &mut attrs,
+                scalar,
+                *layout,
+                offset,
+                is_return,
+                is_drop_target,
+            );
             attrs
         });