From 201ae7387245caa4591d4c8db4c35c170c64faf0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Dec 2022 12:31:17 +0100 Subject: [PATCH] make PointerKind directly reflect pointer types The code that consumes PointerKind (`adjust_for_rust_scalar` in rustc_ty_utils) ended up using PointerKind variants to talk about Rust reference types (& and &mut) anyway, making the old code structure quite confusing: one always had to keep in mind which PointerKind corresponds to which type. So this changes PointerKind to directly reflect the type. This does not change behavior. --- compiler/rustc_abi/src/lib.rs | 21 ++++-------- compiler/rustc_middle/src/ty/layout.rs | 39 +++++++---------------- compiler/rustc_ty_utils/src/abi.rs | 33 ++++++++++--------- tests/codegen/function-arguments-noopt.rs | 6 ++++ 4 files changed, 40 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 5af6206c0bb8..9126c516d381 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1439,21 +1439,12 @@ impl fmt::Debug for LayoutS { #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PointerKind { - /// Most general case, we know no restrictions to tell LLVM. - SharedMutable, - - /// `&T` where `T` contains no `UnsafeCell`, is `dereferenceable`, `noalias` and `readonly`. - Frozen, - - /// `&mut T` which is `dereferenceable` and `noalias` but not `readonly`. - UniqueBorrowed, - - /// `&mut !Unpin`, which is `dereferenceable` but neither `noalias` nor `readonly`. - UniqueBorrowedPinned, - - /// `Box`, which is `noalias` (even on return types, unlike the above) but neither `readonly` - /// nor `dereferenceable`. - UniqueOwned, + /// Shared reference. `frozen` indicates the absence of any `UnsafeCell`. + SharedRef { frozen: bool }, + /// Mutable reference. `unpin` indicates the absence of any pinned data. + MutableRef { unpin: bool }, + /// Box. + Box, } /// Note that this information is advisory only, and backends are free to ignore it. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index cdcd6281f209..1244922c6d4a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -833,32 +833,17 @@ where }) } ty::Ref(_, ty, mt) if offset.bytes() == 0 => { - let kind = if tcx.sess.opts.optimize == OptLevel::No { - // Use conservative pointer kind if not optimizing. This saves us the - // Freeze/Unpin queries, and can save time in the codegen backend (noalias - // attributes in LLVM have compile-time cost even in unoptimized builds). - PointerKind::SharedMutable - } else { - match mt { - hir::Mutability::Not => { - if ty.is_freeze(tcx, cx.param_env()) { - PointerKind::Frozen - } else { - PointerKind::SharedMutable - } - } - hir::Mutability::Mut => { - // References to self-referential structures should not be considered - // noalias, as another pointer to the structure can be obtained, that - // is not based-on the original reference. We consider all !Unpin - // types to be potentially self-referential here. - if ty.is_unpin(tcx, cx.param_env()) { - PointerKind::UniqueBorrowed - } else { - PointerKind::UniqueBorrowedPinned - } - } - } + // Use conservative pointer kind if not optimizing. This saves us the + // Freeze/Unpin queries, and can save time in the codegen backend (noalias + // attributes in LLVM have compile-time cost even in unoptimized builds). + let optimize = tcx.sess.opts.optimize != OptLevel::No; + let kind = match mt { + hir::Mutability::Not => PointerKind::SharedRef { + frozen: optimize && ty.is_freeze(tcx, cx.param_env()), + }, + hir::Mutability::Mut => PointerKind::MutableRef { + unpin: optimize && ty.is_unpin(tcx, cx.param_env()), + }, }; tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo { @@ -929,7 +914,7 @@ where if let Some(ref mut pointee) = result { if let ty::Adt(def, _) = this.ty.kind() { if def.is_box() && offset.bytes() == 0 { - pointee.safe = Some(PointerKind::UniqueOwned); + pointee.safe = Some(PointerKind::Box); } } } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 1c74aeca5ab1..884087987ce0 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -254,15 +254,15 @@ fn adjust_for_rust_scalar<'tcx>( if let Some(kind) = pointee.safe { attrs.pointee_align = Some(pointee.align); - // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable - // for the entire duration of the function as they can be deallocated - // at any time. Same for shared mutable references. If LLVM had a - // way to say "dereferenceable on entry" we could use it here. + // `Box` are not necessarily dereferenceable for the entire duration of the function as + // they can be deallocated at any time. Same for non-frozen shared references (see + // ). If LLVM had a way to say + // "dereferenceable on entry" we could use it here. attrs.pointee_size = match kind { - PointerKind::UniqueBorrowed - | PointerKind::UniqueBorrowedPinned - | PointerKind::Frozen => pointee.size, - PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO, + PointerKind::Box | PointerKind::SharedRef { frozen: false } => Size::ZERO, + PointerKind::SharedRef { frozen: true } | PointerKind::MutableRef { .. } => { + pointee.size + } }; // The aliasing rules for `Box` are still not decided, but currently we emit @@ -278,15 +278,14 @@ fn adjust_for_rust_scalar<'tcx>( // `&mut` pointer parameters never alias other parameters, // or mutable global data // - // `&T` where `T` contains no `UnsafeCell` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality + // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as both + // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory + // dependencies rather than pointer equality. However this only applies to arguments, + // not return values. let no_alias = match kind { - PointerKind::SharedMutable | PointerKind::UniqueBorrowedPinned => false, - PointerKind::UniqueBorrowed => noalias_mut_ref, - PointerKind::UniqueOwned => noalias_for_box, - PointerKind::Frozen => true, + PointerKind::SharedRef { frozen } => frozen, + PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref, + PointerKind::Box => noalias_for_box, }; // We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics // (see ). @@ -294,7 +293,7 @@ fn adjust_for_rust_scalar<'tcx>( attrs.set(ArgAttribute::NoAlias); } - if kind == PointerKind::Frozen && !is_return { + if matches!(kind, PointerKind::SharedRef { frozen: true }) && !is_return { attrs.set(ArgAttribute::ReadOnly); } } diff --git a/tests/codegen/function-arguments-noopt.rs b/tests/codegen/function-arguments-noopt.rs index ff76405a4ea3..0c62e0d35e36 100644 --- a/tests/codegen/function-arguments-noopt.rs +++ b/tests/codegen/function-arguments-noopt.rs @@ -29,6 +29,12 @@ pub fn borrow(x: &i32) -> &i32 { x } +// CHECK: align 4 {{i32\*|ptr}} @borrow_mut({{i32\*|ptr}} align 4 %x) +#[no_mangle] +pub fn borrow_mut(x: &mut i32) -> &mut i32 { + x +} + // CHECK-LABEL: @borrow_call #[no_mangle] pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {