Skip to content

Commit 3e84ba2

Browse files
authored
Rollup merge of rust-lang#144192 - RalfJung:atomicrmw-ptr, r=nikic
atomicrmw on pointers: move integer-pointer cast hacks into backend Conceptually, we want to have atomic operations on pointers of the form `fn atomic_add(ptr: *mut T, offset: usize, ...)`. However, LLVM does not directly support such operations (llvm/llvm-project#120837), so we have to cast the `offset` to a pointer somewhere. This PR moves that hack into the LLVM backend, so that the standard library, intrinsic, and Miri all work with the conceptual operation we actually want. Hopefully, one day LLVM will gain a way to represent these operations without integer-pointer casts, and then the hack will disappear entirely. Cc ```@nikic``` -- this is the best we can do right now, right? Fixes rust-lang#134617
2 parents a71ec16 + 33057d9 commit 3e84ba2

File tree

2 files changed

+57
-62
lines changed

2 files changed

+57
-62
lines changed

core/src/intrinsics/mod.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -150,69 +150,63 @@ pub unsafe fn atomic_xchg<T: Copy, const ORD: AtomicOrdering>(dst: *mut T, src:
150150

151151
/// Adds to the current value, returning the previous value.
152152
/// `T` must be an integer or pointer type.
153-
/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new
154-
/// value stored at `*dst` will have the provenance of the old value stored there.
153+
/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type.
155154
///
156155
/// The stabilized version of this intrinsic is available on the
157156
/// [`atomic`] types via the `fetch_add` method. For example, [`AtomicIsize::fetch_add`].
158157
#[rustc_intrinsic]
159158
#[rustc_nounwind]
160-
pub unsafe fn atomic_xadd<T: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: T) -> T;
159+
pub unsafe fn atomic_xadd<T: Copy, U: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: U) -> T;
161160

162161
/// Subtract from the current value, returning the previous value.
163162
/// `T` must be an integer or pointer type.
164-
/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new
165-
/// value stored at `*dst` will have the provenance of the old value stored there.
163+
/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type.
166164
///
167165
/// The stabilized version of this intrinsic is available on the
168166
/// [`atomic`] types via the `fetch_sub` method. For example, [`AtomicIsize::fetch_sub`].
169167
#[rustc_intrinsic]
170168
#[rustc_nounwind]
171-
pub unsafe fn atomic_xsub<T: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: T) -> T;
169+
pub unsafe fn atomic_xsub<T: Copy, U: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: U) -> T;
172170

173171
/// Bitwise and with the current value, returning the previous value.
174172
/// `T` must be an integer or pointer type.
175-
/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new
176-
/// value stored at `*dst` will have the provenance of the old value stored there.
173+
/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type.
177174
///
178175
/// The stabilized version of this intrinsic is available on the
179176
/// [`atomic`] types via the `fetch_and` method. For example, [`AtomicBool::fetch_and`].
180177
#[rustc_intrinsic]
181178
#[rustc_nounwind]
182-
pub unsafe fn atomic_and<T: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: T) -> T;
179+
pub unsafe fn atomic_and<T: Copy, U: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: U) -> T;
183180

184181
/// Bitwise nand with the current value, returning the previous value.
185182
/// `T` must be an integer or pointer type.
186-
/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new
187-
/// value stored at `*dst` will have the provenance of the old value stored there.
183+
/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type.
188184
///
189185
/// The stabilized version of this intrinsic is available on the
190186
/// [`AtomicBool`] type via the `fetch_nand` method. For example, [`AtomicBool::fetch_nand`].
191187
#[rustc_intrinsic]
192188
#[rustc_nounwind]
193-
pub unsafe fn atomic_nand<T: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: T) -> T;
189+
pub unsafe fn atomic_nand<T: Copy, U: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: U) -> T;
194190

195191
/// Bitwise or with the current value, returning the previous value.
196192
/// `T` must be an integer or pointer type.
197-
/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new
198-
/// value stored at `*dst` will have the provenance of the old value stored there.
193+
/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type.
199194
///
200195
/// The stabilized version of this intrinsic is available on the
201196
/// [`atomic`] types via the `fetch_or` method. For example, [`AtomicBool::fetch_or`].
202197
#[rustc_intrinsic]
203198
#[rustc_nounwind]
204-
pub unsafe fn atomic_or<T: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: T) -> T;
199+
pub unsafe fn atomic_or<T: Copy, U: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: U) -> T;
205200

206201
/// Bitwise xor with the current value, returning the previous value.
207202
/// `T` must be an integer or pointer type.
208-
/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new
209-
/// value stored at `*dst` will have the provenance of the old value stored there.
203+
/// `U` must be the same as `T` if that is an integer type, or `usize` if `T` is a pointer type.
210204
///
211205
/// The stabilized version of this intrinsic is available on the
212206
/// [`atomic`] types via the `fetch_xor` method. For example, [`AtomicBool::fetch_xor`].
213207
#[rustc_intrinsic]
214208
#[rustc_nounwind]
215-
pub unsafe fn atomic_xor<T: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: T) -> T;
209+
pub unsafe fn atomic_xor<T: Copy, U: Copy, const ORD: AtomicOrdering>(dst: *mut T, src: U) -> T;
216210

217211
/// Maximum with the current value using a signed comparison.
218212
/// `T` must be a signed integer type.

core/src/sync/atomic.rs

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,7 +2293,7 @@ impl<T> AtomicPtr<T> {
22932293
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
22942294
pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T {
22952295
// SAFETY: data races are prevented by atomic intrinsics.
2296-
unsafe { atomic_add(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() }
2296+
unsafe { atomic_add(self.p.get(), val, order).cast() }
22972297
}
22982298

22992299
/// Offsets the pointer's address by subtracting `val` *bytes*, returning the
@@ -2318,17 +2318,18 @@ impl<T> AtomicPtr<T> {
23182318
/// #![feature(strict_provenance_atomic_ptr)]
23192319
/// use core::sync::atomic::{AtomicPtr, Ordering};
23202320
///
2321-
/// let atom = AtomicPtr::<i64>::new(core::ptr::without_provenance_mut(1));
2322-
/// assert_eq!(atom.fetch_byte_sub(1, Ordering::Relaxed).addr(), 1);
2323-
/// assert_eq!(atom.load(Ordering::Relaxed).addr(), 0);
2321+
/// let mut arr = [0i64, 1];
2322+
/// let atom = AtomicPtr::<i64>::new(&raw mut arr[1]);
2323+
/// assert_eq!(atom.fetch_byte_sub(8, Ordering::Relaxed).addr(), (&raw const arr[1]).addr());
2324+
/// assert_eq!(atom.load(Ordering::Relaxed).addr(), (&raw const arr[0]).addr());
23242325
/// ```
23252326
#[inline]
23262327
#[cfg(target_has_atomic = "ptr")]
23272328
#[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
23282329
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
23292330
pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T {
23302331
// SAFETY: data races are prevented by atomic intrinsics.
2331-
unsafe { atomic_sub(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() }
2332+
unsafe { atomic_sub(self.p.get(), val, order).cast() }
23322333
}
23332334

23342335
/// Performs a bitwise "or" operation on the address of the current pointer,
@@ -2379,7 +2380,7 @@ impl<T> AtomicPtr<T> {
23792380
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
23802381
pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T {
23812382
// SAFETY: data races are prevented by atomic intrinsics.
2382-
unsafe { atomic_or(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() }
2383+
unsafe { atomic_or(self.p.get(), val, order).cast() }
23832384
}
23842385

23852386
/// Performs a bitwise "and" operation on the address of the current
@@ -2429,7 +2430,7 @@ impl<T> AtomicPtr<T> {
24292430
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
24302431
pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T {
24312432
// SAFETY: data races are prevented by atomic intrinsics.
2432-
unsafe { atomic_and(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() }
2433+
unsafe { atomic_and(self.p.get(), val, order).cast() }
24332434
}
24342435

24352436
/// Performs a bitwise "xor" operation on the address of the current
@@ -2477,7 +2478,7 @@ impl<T> AtomicPtr<T> {
24772478
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
24782479
pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
24792480
// SAFETY: data races are prevented by atomic intrinsics.
2480-
unsafe { atomic_xor(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() }
2481+
unsafe { atomic_xor(self.p.get(), val, order).cast() }
24812482
}
24822483

24832484
/// Returns a mutable pointer to the underlying pointer.
@@ -3981,15 +3982,15 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
39813982
#[inline]
39823983
#[cfg(target_has_atomic)]
39833984
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3984-
unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
3985+
unsafe fn atomic_add<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
39853986
// SAFETY: the caller must uphold the safety contract for `atomic_add`.
39863987
unsafe {
39873988
match order {
3988-
Relaxed => intrinsics::atomic_xadd::<T, { AO::Relaxed }>(dst, val),
3989-
Acquire => intrinsics::atomic_xadd::<T, { AO::Acquire }>(dst, val),
3990-
Release => intrinsics::atomic_xadd::<T, { AO::Release }>(dst, val),
3991-
AcqRel => intrinsics::atomic_xadd::<T, { AO::AcqRel }>(dst, val),
3992-
SeqCst => intrinsics::atomic_xadd::<T, { AO::SeqCst }>(dst, val),
3989+
Relaxed => intrinsics::atomic_xadd::<T, U, { AO::Relaxed }>(dst, val),
3990+
Acquire => intrinsics::atomic_xadd::<T, U, { AO::Acquire }>(dst, val),
3991+
Release => intrinsics::atomic_xadd::<T, U, { AO::Release }>(dst, val),
3992+
AcqRel => intrinsics::atomic_xadd::<T, U, { AO::AcqRel }>(dst, val),
3993+
SeqCst => intrinsics::atomic_xadd::<T, U, { AO::SeqCst }>(dst, val),
39933994
}
39943995
}
39953996
}
@@ -3998,15 +3999,15 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
39983999
#[inline]
39994000
#[cfg(target_has_atomic)]
40004001
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4001-
unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
4002+
unsafe fn atomic_sub<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
40024003
// SAFETY: the caller must uphold the safety contract for `atomic_sub`.
40034004
unsafe {
40044005
match order {
4005-
Relaxed => intrinsics::atomic_xsub::<T, { AO::Relaxed }>(dst, val),
4006-
Acquire => intrinsics::atomic_xsub::<T, { AO::Acquire }>(dst, val),
4007-
Release => intrinsics::atomic_xsub::<T, { AO::Release }>(dst, val),
4008-
AcqRel => intrinsics::atomic_xsub::<T, { AO::AcqRel }>(dst, val),
4009-
SeqCst => intrinsics::atomic_xsub::<T, { AO::SeqCst }>(dst, val),
4006+
Relaxed => intrinsics::atomic_xsub::<T, U, { AO::Relaxed }>(dst, val),
4007+
Acquire => intrinsics::atomic_xsub::<T, U, { AO::Acquire }>(dst, val),
4008+
Release => intrinsics::atomic_xsub::<T, U, { AO::Release }>(dst, val),
4009+
AcqRel => intrinsics::atomic_xsub::<T, U, { AO::AcqRel }>(dst, val),
4010+
SeqCst => intrinsics::atomic_xsub::<T, U, { AO::SeqCst }>(dst, val),
40104011
}
40114012
}
40124013
}
@@ -4147,63 +4148,63 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>(
41474148
#[inline]
41484149
#[cfg(target_has_atomic)]
41494150
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4150-
unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
4151+
unsafe fn atomic_and<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
41514152
// SAFETY: the caller must uphold the safety contract for `atomic_and`
41524153
unsafe {
41534154
match order {
4154-
Relaxed => intrinsics::atomic_and::<T, { AO::Relaxed }>(dst, val),
4155-
Acquire => intrinsics::atomic_and::<T, { AO::Acquire }>(dst, val),
4156-
Release => intrinsics::atomic_and::<T, { AO::Release }>(dst, val),
4157-
AcqRel => intrinsics::atomic_and::<T, { AO::AcqRel }>(dst, val),
4158-
SeqCst => intrinsics::atomic_and::<T, { AO::SeqCst }>(dst, val),
4155+
Relaxed => intrinsics::atomic_and::<T, U, { AO::Relaxed }>(dst, val),
4156+
Acquire => intrinsics::atomic_and::<T, U, { AO::Acquire }>(dst, val),
4157+
Release => intrinsics::atomic_and::<T, U, { AO::Release }>(dst, val),
4158+
AcqRel => intrinsics::atomic_and::<T, U, { AO::AcqRel }>(dst, val),
4159+
SeqCst => intrinsics::atomic_and::<T, U, { AO::SeqCst }>(dst, val),
41594160
}
41604161
}
41614162
}
41624163

41634164
#[inline]
41644165
#[cfg(target_has_atomic)]
41654166
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4166-
unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
4167+
unsafe fn atomic_nand<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
41674168
// SAFETY: the caller must uphold the safety contract for `atomic_nand`
41684169
unsafe {
41694170
match order {
4170-
Relaxed => intrinsics::atomic_nand::<T, { AO::Relaxed }>(dst, val),
4171-
Acquire => intrinsics::atomic_nand::<T, { AO::Acquire }>(dst, val),
4172-
Release => intrinsics::atomic_nand::<T, { AO::Release }>(dst, val),
4173-
AcqRel => intrinsics::atomic_nand::<T, { AO::AcqRel }>(dst, val),
4174-
SeqCst => intrinsics::atomic_nand::<T, { AO::SeqCst }>(dst, val),
4171+
Relaxed => intrinsics::atomic_nand::<T, U, { AO::Relaxed }>(dst, val),
4172+
Acquire => intrinsics::atomic_nand::<T, U, { AO::Acquire }>(dst, val),
4173+
Release => intrinsics::atomic_nand::<T, U, { AO::Release }>(dst, val),
4174+
AcqRel => intrinsics::atomic_nand::<T, U, { AO::AcqRel }>(dst, val),
4175+
SeqCst => intrinsics::atomic_nand::<T, U, { AO::SeqCst }>(dst, val),
41754176
}
41764177
}
41774178
}
41784179

41794180
#[inline]
41804181
#[cfg(target_has_atomic)]
41814182
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4182-
unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
4183+
unsafe fn atomic_or<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
41834184
// SAFETY: the caller must uphold the safety contract for `atomic_or`
41844185
unsafe {
41854186
match order {
4186-
SeqCst => intrinsics::atomic_or::<T, { AO::SeqCst }>(dst, val),
4187-
Acquire => intrinsics::atomic_or::<T, { AO::Acquire }>(dst, val),
4188-
Release => intrinsics::atomic_or::<T, { AO::Release }>(dst, val),
4189-
AcqRel => intrinsics::atomic_or::<T, { AO::AcqRel }>(dst, val),
4190-
Relaxed => intrinsics::atomic_or::<T, { AO::Relaxed }>(dst, val),
4187+
SeqCst => intrinsics::atomic_or::<T, U, { AO::SeqCst }>(dst, val),
4188+
Acquire => intrinsics::atomic_or::<T, U, { AO::Acquire }>(dst, val),
4189+
Release => intrinsics::atomic_or::<T, U, { AO::Release }>(dst, val),
4190+
AcqRel => intrinsics::atomic_or::<T, U, { AO::AcqRel }>(dst, val),
4191+
Relaxed => intrinsics::atomic_or::<T, U, { AO::Relaxed }>(dst, val),
41914192
}
41924193
}
41934194
}
41944195

41954196
#[inline]
41964197
#[cfg(target_has_atomic)]
41974198
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4198-
unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
4199+
unsafe fn atomic_xor<T: Copy, U: Copy>(dst: *mut T, val: U, order: Ordering) -> T {
41994200
// SAFETY: the caller must uphold the safety contract for `atomic_xor`
42004201
unsafe {
42014202
match order {
4202-
SeqCst => intrinsics::atomic_xor::<T, { AO::SeqCst }>(dst, val),
4203-
Acquire => intrinsics::atomic_xor::<T, { AO::Acquire }>(dst, val),
4204-
Release => intrinsics::atomic_xor::<T, { AO::Release }>(dst, val),
4205-
AcqRel => intrinsics::atomic_xor::<T, { AO::AcqRel }>(dst, val),
4206-
Relaxed => intrinsics::atomic_xor::<T, { AO::Relaxed }>(dst, val),
4203+
SeqCst => intrinsics::atomic_xor::<T, U, { AO::SeqCst }>(dst, val),
4204+
Acquire => intrinsics::atomic_xor::<T, U, { AO::Acquire }>(dst, val),
4205+
Release => intrinsics::atomic_xor::<T, U, { AO::Release }>(dst, val),
4206+
AcqRel => intrinsics::atomic_xor::<T, U, { AO::AcqRel }>(dst, val),
4207+
Relaxed => intrinsics::atomic_xor::<T, U, { AO::Relaxed }>(dst, val),
42074208
}
42084209
}
42094210
}

0 commit comments

Comments
 (0)