Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
sym::atomic_load => {
intrinsic_args!(fx, args => (ptr); intrinsic);
let ptr = ptr.load_scalar(fx);
// FIXME: this ignores the atomic ordering and the volatile flag.

let ty = generic_args.type_at(0);
match ty.kind() {
Expand Down Expand Up @@ -908,6 +909,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
sym::atomic_store => {
intrinsic_args!(fx, args => (ptr, val); intrinsic);
let ptr = ptr.load_scalar(fx);
// FIXME: this ignores the atomic ordering and the volatile flag.

let ty = generic_args.type_at(0);
match ty.kind() {
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,13 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
AtomicOrdering::AcqRel | AtomicOrdering::Release => AtomicOrdering::Acquire,
_ => order,
};
let previous_value =
self.atomic_load(dst.get_type(), dst, load_ordering, Size::from_bytes(size));
let previous_value = self.atomic_load(
dst.get_type(),
dst,
load_ordering,
/* volatile */ false,
Size::from_bytes(size),
);
let previous_var =
func.new_local(self.location, previous_value.get_type(), "previous_value");
let return_value = func.new_local(self.location, previous_value.get_type(), "return_value");
Expand Down Expand Up @@ -1008,6 +1013,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
_ty: Type<'gcc>,
ptr: RValue<'gcc>,
order: AtomicOrdering,
_volatile: bool, // FIXME we are ignoring this
size: Size,
) -> RValue<'gcc> {
// FIXME(antoyo): use ty.
Expand Down Expand Up @@ -1177,6 +1183,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
value: RValue<'gcc>,
ptr: RValue<'gcc>,
order: AtomicOrdering,
_volatile: bool, // FIXME we are ignoring this
size: Size,
) {
// FIXME(antoyo): handle alignment.
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,12 +703,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
ty: &'ll Type,
ptr: &'ll Value,
order: rustc_middle::ty::AtomicOrdering,
volatile: bool,
size: Size,
) -> &'ll Value {
unsafe {
let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED);
// Set atomic ordering
llvm::LLVMSetOrdering(load, AtomicOrdering::from_generic(order));
if volatile {
llvm::LLVMSetVolatile(load, llvm::TRUE);
}
// LLVM requires the alignment of atomic loads to be at least the size of the type.
llvm::LLVMSetAlignment(load, size.bytes() as c_uint);
load
Expand Down Expand Up @@ -930,6 +934,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
val: &'ll Value,
ptr: &'ll Value,
order: rustc_middle::ty::AtomicOrdering,
volatile: bool,
size: Size,
) {
debug!("Store {:?} -> {:?}", val, ptr);
Expand All @@ -938,6 +943,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
// Set atomic ordering
llvm::LLVMSetOrdering(store, AtomicOrdering::from_generic(order));
if volatile {
llvm::LLVMSetVolatile(store, llvm::TRUE);
}
// LLVM requires the alignment of atomic stores to be at least the size of the type.
llvm::LLVMSetAlignment(store, size.bytes() as c_uint);
}
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return IntrinsicResult::Err(err);
}
let ordering = fn_args.const_at(1).to_value();
let volatile = fn_args.const_at(2).to_value();
let layout = bx.layout_of(ty);
let source = args[0].immediate();
OperandValue::Immediate(bx.atomic_load(
bx.backend_type(layout),
source,
parse_atomic_ordering(ordering),
volatile.to_leaf().try_to_bool().unwrap(),
layout.size,
))
}
Expand All @@ -397,10 +399,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return IntrinsicResult::Err(err);
}
let ordering = fn_args.const_at(1).to_value();
let volatile = fn_args.const_at(2).to_value();
let size = bx.layout_of(ty).size;
let val = args[1].immediate();
let ptr = args[0].immediate();
bx.atomic_store(val, ptr, parse_atomic_ordering(ordering), size);
bx.atomic_store(
val,
ptr,
parse_atomic_ordering(ordering),
volatile.to_leaf().try_to_bool().unwrap(),
size,
);
OperandValue::ZeroSized
}
// These are all AtomicRMW ops
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/src/traits/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ pub trait BuilderMethods<'a, 'tcx>:
ty: Self::Type,
ptr: Self::Value,
order: AtomicOrdering,
volatile: bool,
size: Size,
) -> Self::Value;
fn load_from_place(&mut self, ty: Self::Type, place: PlaceValue<Self::Value>) -> Self::Value {
Expand Down Expand Up @@ -330,6 +331,7 @@ pub trait BuilderMethods<'a, 'tcx>:
val: Self::Value,
ptr: Self::Value,
order: AtomicOrdering,
volatile: bool,
size: Size,
);

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/src/interpret/intrinsics/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
match intrinsic_name {
sym::atomic_load => {
let ord = get_ord_at(1);
let _volatile = generic_args.const_at(2).to_value(); // makes no difference for us
let [ptr] = args else { span_bug!(self.cur_span(), "invalid `atomic_load` call") };

let place = self.deref_pointer(ptr)?;
Expand All @@ -35,6 +36,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
sym::atomic_store => {
let ord = get_ord_at(1);
let _volatile = generic_args.const_at(2).to_value(); // makes no difference for us
let [ptr, val] = args else {
span_bug!(self.cur_span(), "invalid `atomic_store` call")
};
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,8 +790,8 @@ pub(crate) fn check_intrinsic_type(
vec![Ty::new_mut_ptr(tcx, param(0)), param(0), param(0)],
Ty::new_tup(tcx, &[param(0), tcx.types.bool]),
),
sym::atomic_load => (1, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
sym::atomic_store => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit),
sym::atomic_load => (1, 2, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
sym::atomic_store => (1, 2, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit),

sym::atomic_xchg
| sym::atomic_max
Expand Down
9 changes: 7 additions & 2 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ pub const unsafe fn atomic_cxchgweak<
/// [`atomic`] types via the `load` method. For example, [`AtomicBool::load`].
#[rustc_intrinsic]
#[rustc_nounwind]
pub const unsafe fn atomic_load<T: Copy, const ORD: AtomicOrdering>(src: *const T) -> T;
pub const unsafe fn atomic_load<T: Copy, const ORD: AtomicOrdering, const VOLATILE: bool>(
src: *const T,
) -> T;

/// Stores the value at the specified memory location.
/// `T` must be an integer or pointer type.
Expand All @@ -139,7 +141,10 @@ pub const unsafe fn atomic_load<T: Copy, const ORD: AtomicOrdering>(src: *const
/// [`atomic`] types via the `store` method. For example, [`AtomicBool::store`].
#[rustc_intrinsic]
#[rustc_nounwind]
pub const unsafe fn atomic_store<T: Copy, const ORD: AtomicOrdering>(dst: *mut T, val: T);
pub const unsafe fn atomic_store<T: Copy, const ORD: AtomicOrdering, const VOLATILE: bool>(
dst: *mut T,
val: T,
);

/// Stores the value at the specified memory location, returning the old value.
/// `T` must be an integer or pointer type.
Expand Down
32 changes: 18 additions & 14 deletions library/core/src/sync/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,9 @@ impl AtomicBool {
pub const fn load(&self, order: Ordering) -> bool {
// SAFETY: any data races are prevented by atomic intrinsics and the raw
// pointer passed in is valid because we got it from a reference.
unsafe { atomic_load(self.v.get().cast::<u8>(), order) != 0 }
unsafe {
atomic_load::<_, /* VOLATILE */ false>(self.v.get().cast::<u8>(), order) != 0
}
}

/// Stores a value into the bool.
Expand Down Expand Up @@ -790,7 +792,7 @@ impl AtomicBool {
// SAFETY: any data races are prevented by atomic intrinsics and the raw
// pointer passed in is valid because we got it from a reference.
unsafe {
atomic_store(self.v.get().cast::<u8>(), val as u8, order);
atomic_store::<_, /* VOLATILE */ false>(self.v.get().cast::<u8>(), val as u8, order);
}
}

Expand Down Expand Up @@ -1762,7 +1764,9 @@ impl<T> AtomicPtr<T> {
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const fn load(&self, order: Ordering) -> *mut T {
// SAFETY: data races are prevented by atomic intrinsics.
unsafe { atomic_load(self.as_ptr(), order) }
unsafe {
atomic_load::<_, /* VOLATILE */ false>(self.as_ptr(), order)
}
}

/// Stores a value into the pointer.
Expand Down Expand Up @@ -1794,7 +1798,7 @@ impl<T> AtomicPtr<T> {
pub const fn store(&self, ptr: *mut T, order: Ordering) {
// SAFETY: data races are prevented by atomic intrinsics.
unsafe {
atomic_store(self.as_ptr(), ptr, order);
atomic_store::<_, /* VOLATILE */ false>(self.as_ptr(), ptr, order);
}
}

Expand Down Expand Up @@ -2913,7 +2917,7 @@ macro_rules! atomic_int {
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const fn load(&self, order: Ordering) -> $int_type {
// SAFETY: data races are prevented by atomic intrinsics.
unsafe { atomic_load(self.as_ptr(), order) }
unsafe { atomic_load::<_, /* VOLATILE */ false>(self.as_ptr(), order) }
}

/// Stores a value into the atomic integer.
Expand Down Expand Up @@ -2943,7 +2947,7 @@ macro_rules! atomic_int {
#[rustc_should_not_be_called_on_const_items]
pub const fn store(&self, val: $int_type, order: Ordering) {
// SAFETY: data races are prevented by atomic intrinsics.
unsafe { atomic_store(self.as_ptr(), val, order); }
unsafe { atomic_store::<_, /* VOLATILE */ false>(self.as_ptr(), val, order); }
}

/// Stores a value into the atomic integer, returning the previous value.
Expand Down Expand Up @@ -3971,13 +3975,13 @@ const fn strongest_failure_ordering(order: Ordering) -> Ordering {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[rustc_const_unstable(feature = "const_atomic", issue = "160078")]
const unsafe fn atomic_store<T: Copy>(dst: *mut T, val: T, order: Ordering) {
const unsafe fn atomic_store<T: Copy, const VOLATILE: bool>(dst: *mut T, val: T, order: Ordering) {
// SAFETY: the caller must uphold the safety contract for `atomic_store`.
unsafe {
match order {
Relaxed => intrinsics::atomic_store::<T, { AO::Relaxed }>(dst, val),
Release => intrinsics::atomic_store::<T, { AO::Release }>(dst, val),
SeqCst => intrinsics::atomic_store::<T, { AO::SeqCst }>(dst, val),
Relaxed => intrinsics::atomic_store::<T, { AO::Relaxed }, VOLATILE>(dst, val),
Release => intrinsics::atomic_store::<T, { AO::Release }, VOLATILE>(dst, val),
SeqCst => intrinsics::atomic_store::<T, { AO::SeqCst }, VOLATILE>(dst, val),
Acquire => panic!("there is no such thing as an acquire store"),
AcqRel => panic!("there is no such thing as an acquire-release store"),
}
Expand All @@ -3987,13 +3991,13 @@ const unsafe fn atomic_store<T: Copy>(dst: *mut T, val: T, order: Ordering) {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[rustc_const_unstable(feature = "const_atomic", issue = "160078")]
const unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T {
const unsafe fn atomic_load<T: Copy, const VOLATILE: bool>(dst: *const T, order: Ordering) -> T {
// SAFETY: the caller must uphold the safety contract for `atomic_load`.
unsafe {
match order {
Relaxed => intrinsics::atomic_load::<T, { AO::Relaxed }>(dst),
Acquire => intrinsics::atomic_load::<T, { AO::Acquire }>(dst),
SeqCst => intrinsics::atomic_load::<T, { AO::SeqCst }>(dst),
Relaxed => intrinsics::atomic_load::<T, { AO::Relaxed }, VOLATILE>(dst),
Acquire => intrinsics::atomic_load::<T, { AO::Acquire }, VOLATILE>(dst),
SeqCst => intrinsics::atomic_load::<T, { AO::SeqCst }, VOLATILE>(dst),
Release => panic!("there is no such thing as a release load"),
AcqRel => panic!("there is no such thing as an acquire-release load"),
}
Expand Down
10 changes: 5 additions & 5 deletions library/panic_unwind/src/seh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,24 +337,24 @@ unsafe fn throw_exception(data: Option<Box<dyn Any + Send>>) -> ! {
// express more operations in statics (and we may never be able to).
unsafe {
#[allow(function_casts_as_integer)]
atomic_store::<_, { AtomicOrdering::SeqCst }>(
atomic_store::<_, { AtomicOrdering::SeqCst }, /* VOLATILE */ false>(
(&raw mut THROW_INFO.pmfnUnwind).cast(),
ptr_t::new(exception_cleanup as *mut u8).raw(),
);
atomic_store::<_, { AtomicOrdering::SeqCst }>(
atomic_store::<_, { AtomicOrdering::SeqCst }, /* VOLATILE */ false>(
(&raw mut THROW_INFO.pCatchableTypeArray).cast(),
ptr_t::new((&raw mut CATCHABLE_TYPE_ARRAY).cast()).raw(),
);
atomic_store::<_, { AtomicOrdering::SeqCst }>(
atomic_store::<_, { AtomicOrdering::SeqCst }, /* VOLATILE */ false>(
(&raw mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(),
ptr_t::new((&raw mut CATCHABLE_TYPE).cast()).raw(),
);
atomic_store::<_, { AtomicOrdering::SeqCst }>(
atomic_store::<_, { AtomicOrdering::SeqCst }, /* VOLATILE */ false>(
(&raw mut CATCHABLE_TYPE.pType).cast(),
ptr_t::new((&raw mut TYPE_DESCRIPTOR).cast()).raw(),
);
#[allow(function_casts_as_integer)]
atomic_store::<_, { AtomicOrdering::SeqCst }>(
atomic_store::<_, { AtomicOrdering::SeqCst }, /* VOLATILE */ false>(
(&raw mut CATCHABLE_TYPE.copyFunction).cast(),
ptr_t::new(exception_copy as *mut u8).raw(),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn main() {
let z = [0u32; 2];
let zptr = &z as *const _ as *const u64;
unsafe {
intrinsics::atomic_load::<_, { intrinsics::AtomicOrdering::SeqCst }>(zptr);
intrinsics::atomic_load::<_, { intrinsics::AtomicOrdering::SeqCst }, false>(zptr);
//~^ERROR: accessing memory with alignment 4, but alignment 8 is required
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
--> tests/fail/unaligned_pointers/atomic_unaligned.rs:LL:CC
|
LL | intrinsics::atomic_load::<_, { intrinsics::AtomicOrdering::SeqCst }>(zptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | intrinsics::atomic_load::<_, { intrinsics::AtomicOrdering::SeqCst }, false>(zptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior
= help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives
Expand Down
24 changes: 24 additions & 0 deletions tests/codegen-llvm/atomic-operations.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Code generation of atomic operations.
//@ compile-flags: -Copt-level=3
#![crate_type = "lib"]
#![feature(core_intrinsics)]

use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering::*;
Expand Down Expand Up @@ -82,3 +83,26 @@ pub fn compare_exchange_weak(w: &AtomicI32) {
let _ = w.compare_exchange_weak(1, 51, SeqCst, Acquire);
let _ = w.compare_exchange_weak(1, 52, SeqCst, SeqCst);
}

// CHECK-LABEL: @atomic_volatile
#[no_mangle]
fn atomic_volatile(w: &AtomicI32) {
use std::intrinsics::*;

let ptr = w.as_ptr();
unsafe {
// CHECK: load atomic volatile i32, ptr %{{.*}} monotonic, align 4
// CHECK: load atomic volatile i32, ptr %{{.*}} acquire, align 4
// CHECK: load atomic volatile i32, ptr %{{.*}} seq_cst, align 4
atomic_load::<_, { AtomicOrdering::Relaxed }, /* VOLATILE */ true>(ptr);
atomic_load::<_, { AtomicOrdering::Acquire }, /* VOLATILE */ true>(ptr);
atomic_load::<_, { AtomicOrdering::SeqCst }, /* VOLATILE */ true>(ptr);

// CHECK: store atomic volatile i32 0, ptr %{{.*}} monotonic, align 4
// CHECK: store atomic volatile i32 0, ptr %{{.*}} release, align 4
// CHECK: store atomic volatile i32 0, ptr %{{.*}} seq_cst, align 4
atomic_store::<_, { AtomicOrdering::Relaxed }, /* VOLATILE */ true>(ptr, 0);
atomic_store::<_, { AtomicOrdering::Release }, /* VOLATILE */ true>(ptr, 0);
atomic_store::<_, { AtomicOrdering::SeqCst }, /* VOLATILE */ true>(ptr, 0);
}
}
8 changes: 4 additions & 4 deletions tests/ui/intrinsics/intrinsic-atomics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ pub fn main() {
unsafe {
let mut x: Box<_> = Box::new(1);

assert_eq!(rusti::atomic_load::<_, { SeqCst }>(&*x), 1);
assert_eq!(rusti::atomic_load::<_, { SeqCst }, false>(&*x), 1);
*x = 5;
assert_eq!(rusti::atomic_load::<_, { Acquire }>(&*x), 5);
assert_eq!(rusti::atomic_load::<_, { Acquire }, false>(&*x), 5);

rusti::atomic_store::<_, { SeqCst }>(&mut *x, 3);
rusti::atomic_store::<_, { SeqCst }, false>(&mut *x, 3);
assert_eq!(*x, 3);
rusti::atomic_store::<_, { Release }>(&mut *x, 1);
rusti::atomic_store::<_, { Release }, false>(&mut *x, 1);
assert_eq!(*x, 1);

assert_eq!(rusti::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(&mut *x, 1, 2), (1, true));
Expand Down
Loading
Loading